调优LangChain SQL Agent执行器,使其优先返回姓名而非ID字段
调优LangChain SQL Agent执行器,使其优先返回姓名而非ID字段
我明白你遇到的问题了——SQL Agent有时候会在回答“谁卖得最多?”这类问题时返回用户ID而非姓名,确实挺影响体验的。结合LangChain的配置方式,这里有几个可行的调优方案,你可以试试:
方案一:自定义Prompt模板,给Agent明确指令
SQL Agent的行为很大程度上由Prompt控制,我们可以在系统提示里加入清晰的规则,直接告诉它遇到这类人员相关的问题时要返回姓名而非ID。
from langchain_openai import ChatOpenAI from langchain.agents.agent_toolkits import SQLDatabaseToolkit from langchain.agents import create_sql_agent from langchain.sql_database import SQLDatabase from langchain.prompts import PromptTemplate # 初始化数据库和LLM db = SQLDatabase.from_uri("你的数据库URI") llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0) toolkit = SQLDatabaseToolkit(db=db, llm=llm) # 自定义Prompt,加入明确的返回规则 custom_prompt = PromptTemplate.from_template(""" 你是一个专业的SQL查询助手,负责回答关于数据库的问题。请严格遵循以下规则: 1. 当被问到类似“谁卖得最多?”“哪个用户完成了XX操作?”这类涉及具体人员的问题时,**必须返回该人员的全名(first_name + last_name),绝对不要返回用户ID或其他内部标识字段**。 2. 如果需要关联其他表获取姓名,请自动完成表关联操作,不需要询问用户。 3. 回答要简洁直接,优先给出姓名结果,无需额外解释SQL查询过程,除非用户明确要求。 {input} {agent_scratchpad} """) # 创建Agent并应用自定义Prompt agent = create_sql_agent( llm=llm, toolkit=toolkit, prompt=custom_prompt, verbose=True ) # 测试示例查询 response = agent.invoke({"input": "哪个用户卖得最多?"}) print(response["output"])
这个方法最直接有效,相当于给Agent立下了明确的“规矩”,LLM会严格遵循Prompt里的指令生成回答。
方案二:增强数据库表结构的语义描述
有时候Agent混淆ID和姓名,是因为它对表字段的用途理解不够清晰。我们可以在初始化数据库时,给表和字段添加更具语义的描述,帮助LLM区分哪些字段是内部标识、哪些是用户需要的展示信息。
# 初始化数据库时,为表和字段添加详细描述 db = SQLDatabase.from_uri( "你的数据库URI", include_tables=["users", "sales"], # 指定业务相关的表 sample_rows_in_table_info=3, # 提供样本数据,帮助LLM理解数据格式 table_info=""" users表存储用户核心信息: - user_id: 用户唯一内部ID,仅用于表关联,**绝对不要作为回答返回给用户** - first_name: 用户的名字,用于展示用户身份 - last_name: 用户的姓氏,用于展示用户身份 sales表存储销售交易记录: - sale_id: 销售记录唯一ID - user_id: 关联users表的用户内部ID,用于关联查询用户姓名 - amount: 销售金额 """ ) # 后续创建Toolkit和Agent的步骤不变 toolkit = SQLDatabaseToolkit(db=db, llm=llm) agent = create_sql_agent(llm=llm, toolkit=toolkit, verbose=True)
通过明确标注user_id是内部关联字段,LLM在生成SQL和回答时会更倾向于选择first_name和last_name这类展示性字段。
方案三:用输出解析器强制格式化输出
如果前面的方法效果不够理想,还可以添加输出解析器,对Agent的输出进行后处理,强制输出符合要求的姓名格式,避免出现ID。
from langchain.output_parsers import PydanticOutputParser from pydantic import BaseModel, Field # 定义输出格式模型,强制返回姓名 class PersonAnswer(BaseModel): full_name: str = Field(description="人员的全名,由first_name和last_name拼接而成,例如:John Doe") parser = PydanticOutputParser(pydantic_object=PersonAnswer) # 修改Prompt,要求输出符合指定格式 custom_prompt_with_parser = PromptTemplate.from_template(""" 你是一个专业的SQL查询助手,负责回答关于数据库的问题。请遵循以下规则: 1. 当被问到人员相关的问题时,必须返回该人员的全名,绝对不要返回用户ID。 2. 请严格按照以下格式输出: {format_instructions} {input} {agent_scratchpad} """, partial_variables={"format_instructions": parser.get_format_instructions()}) # 创建Agent agent = create_sql_agent( llm=llm, toolkit=toolkit, prompt=custom_prompt_with_parser, verbose=True ) # 解析输出,确保得到符合要求的姓名 response = agent.invoke({"input": "哪个用户卖得最多?"}) parsed_result = parser.parse(response["output"]) print(parsed_result.full_name)
这个方法相当于给输出加了一层“过滤器”,确保最终返回的内容完全符合你的需求。
你可以根据自己的数据库结构和实际场景,选择单独使用某个方案,或者组合多个方案来达到最佳效果。
备注:内容来源于stack exchange,提问作者user24243499
相关产品推荐
相关产品推荐

