python3 -m venv .venv
source .venv/bin/activate
pip install langchain_community
pip install langchain_core
pip install langchain
#!/usr/bin/env python3
from typing import List, Tuple

from langchain.chains import ConversationChain
#https://python.langchain.com/docs/integrations/toolkits/sql_database
from langchain_community.agent_toolkits import create_sql_agent
from langchain_community.agent_toolkits import SQLDatabaseToolkit
from langchain.agents.agent_types import AgentType
from langchain.sql_database import SQLDatabase
# LangChain supports many other chat models. Here, we're using Ollama
from langchain_community.chat_models import ChatOllama

ollama_llm = ChatOllama(model="gemma:7b")

# sqlite> PRAGMA table_info(notes);
# 0|created_on|DATETIME|1||0
# 1|changed_on|DATETIME|1||0
# 2|id|INTEGER|1||1
# 3|title|VARCHAR(256)|0||0
# 4|content|TEXT|0||0
# 5|created_by_fk|INTEGER|1||0
# 6|changed_by_fk|INTEGER|1||0
# sqlite> 
db = SQLDatabase.from_uri("sqlite:///app.db")
#toolkit = SQLDatabaseToolkit(db=db)

agent_executor = create_sql_agent(
    llm=ollama_llm,
    db=db,
    verbose=True,
    agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION
)

# agent_executor.invoke("请列出notes表里从标题来分类,你觉得有可能是菜谱的记录")
agent_executor.invoke("""取出notes表100个记录的title字段""")

嗯,100%都是会报错的

需要一点一点的去排查错误,就很烦的,就给你说现在的LLM工具简直就是处于不可用状态居多

都需要针对模型去调教


import re
from typing import Union

from langchain_core.agents import AgentAction, AgentFinish
from langchain_core.exceptions import OutputParserException

from langchain.agents.agent import AgentOutputParser
from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS

FINAL_ANSWER_ACTION = "Final Answer:"
FINAL_SUMMARY = "## Summary"
MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE = (
    "Invalid Format: Missing 'Action:' after 'Thought:"
)
MISSING_ACTION_INPUT_AFTER_ACTION_ERROR_MESSAGE = (
    "Invalid Format: Missing 'Action Input:' after 'Action:'"
)
FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE = (
    "Parsing LLM output produced both a final answer and a parse-able action:"
)


class ReActSingleInputOutputParser(AgentOutputParser):
    """Parses ReAct-style LLM calls that have a single tool input.

    Expects output to be in one of two formats.

    If the output signals that an action should be taken,
    should be in the below format. This will result in an AgentAction
    being returned.

    ```
    Thought: agent thought here
    Action: search
    Action Input: what is the temperature in SF?
    ```

    If the output signals that a final answer should be given,
    should be in the below format. This will result in an AgentFinish
    being returned.

    ```
    Thought: agent thought here
    Final Answer: The temperature is 100 degrees
    ```

    """

    def get_format_instructions(self) -> str:
        return FORMAT_INSTRUCTIONS

    def parse(self, text: str) -> Union[AgentAction, AgentFinish]:
        includes_answer = FINAL_ANSWER_ACTION in text
        includes_summary =FINAL_SUMMARY in text
        regex = (
            r"\*\*Action\s*\d*\s*:\*\*[\s]*(.*?)[\s]*\*\*Action\s*\d*\s*Input\s*\d*\s*:\*\*\s*(.*?)\*\*Observation"
        )
        action_match = re.search(regex, text, re.DOTALL)
        if action_match:
            if False:
                raise OutputParserException(
                    f"{FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE}: {text}"
                )
            action = action_match.group(1).strip()
            action_input = action_match.group(2)
            action_input = action_input.strip("\n")
            tool_input = action_input.strip(" ")
            tool_input = tool_input.strip('"')

            return AgentAction(action, tool_input, text)

        elif includes_summary:
            return AgentFinish(
                {"output": text.split(FINAL_ANSWER_ACTION)[-1].strip()}, text
            )
        print("\n================啥?76行到底发生了啥事情?==================")
        print(text)
        rrr1 = re.search(r"\*\*Action\s*\d*\s*:\*\*[\s]*(.*?)", text, re.DOTALL)
        print("================rrr1==================")
        print(rrr1)
        print("================END OF 啥?76行到底发生了啥事情?==================")

        if not re.search(r"\*\*Action\s*\d*\s*:\*\*[\s]*(.*?)", text, re.DOTALL):
            raise OutputParserException(
                f"Could not parse LLM output: `{text}`",
                observation=MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE,
                llm_output=text,
                send_to_llm=True,
            )
        elif not re.search(
            r"\*\*Action\s*\d*\s*Input\s*\d*\s*:\*\*\s*(.*?)", text, re.DOTALL
        ):
            raise OutputParserException(
                f"Could not parse LLM output: `{text}`",
                observation=MISSING_ACTION_INPUT_AFTER_ACTION_ERROR_MESSAGE,
                llm_output=text,
                send_to_llm=True,
            )
        else:
            raise OutputParserException(f"Could not parse LLM output: `{text}`")

    @property
    def _type(self) -> str:
        return "react-single-input"

这是转为gemma准备好的outputParser.py

哎,真烦人