当前位置: 首页 > news >正文

LangChain 实践3 5无Function Call的结构化通用Agent 6Function Call 智能工具助手

项目5 无Function Call的结构化通用Agent

知识点:结构化Agent、Prompt工程、不支持Function Call模型适配、自定义工具

功能

  • 自己写 Prompt 约束格式:Action:xxx Action Input:xxx
  • 不用模型原生Function Call,纯提示词实现工具调用
  • 接入:计算器、时间查询、本地文档检索工具

落地:结构化Agent不靠模型,靠Prompt实现Agent。

项目拆解

核心定位:纯 Prompt 工程实现 Agent 工具调用,零模型原生函数调用能力。

  • 阶段一:项目基础协议定义(前置基建,无代码)
    • 步骤 1:定义 Agent 结构化交互协议(项目核心标准)
    • 实践:统一模型输出字段、工具调用格式、问答分支规则
    • 配套理论:无 Function Call Agent 的结构化解析原理
  • 阶段二:Prompt 工程实现(Agent 大脑规则层)
    • 步骤 2:手写完整版结构化约束 System Prompt
    • 实践:编写角色规则、工具清单、判断逻辑、正负样例、输出规约
    • 配套理论:Prompt 工程如何替代原生 Function Call 能力
  • 阶段三:代码基建(核心底座,Python)
    • 步骤 3:搭建项目基础代码结构,初始化全局配置
    • 实践:创建项目文件结构、导入依赖、定义全局常量
    • 配套理论:模块化 Agent 工程的分层设计思想
  • 阶段四:核心能力开发(工具层)
    • 步骤 4:开发 3 个自定义原生工具
    • 实践:逐一对接实现 calculator、time_query、doc_search 工具函数
    • 配套理论:自定义工具的入参、出参标准化设计规范
  • 阶段五:Agent 核心逻辑(解析 + 调度层)
    • 步骤 5:开发文本格式解析器
    • 实践:代码解析模型输出,提取 Thought / Action / Action Input
    • 配套理论:结构化输出的正则匹配解析原理
    • 步骤 6:开发工具路由调度器
    • 实践:根据解析出的 Action 名称,自动分发执行对应工具
    • 配套理论:Agent 工具调度的路由机制
  • 阶段六:Agent 闭环能力(多轮迭代)
    • 步骤 7:实现单轮 Agent 调用链路
    • 实践:用户提问→模型推理→工具调用→结果返回
    • 步骤 8:实现多轮 Agent 思考闭环
    • 实践:工具结果回传模型,支持多次连续调用工具,直至问题解决
    • 配套理论:Agent ReAct 思考迭代框架核心逻辑
  • 阶段七:测试落地
    • 步骤 9:全场景功能测试、异常兼容优化
    • 实践:测试计算、时间、文档检索、无需工具直接回答、格式异常场景

本项目属于独立可复用的工具调度模块。
整体层级关系:

  • 上层:大模型负责思考决策、输出规范格式文本
  • 中层:咱们写的解析 + 调度逻辑,拆解指令、匹配工具
  • 底层:计算器、文档查询这类具体功能函数

本项目承接模型指令,落地实际操作,是完整智能体里的执行环节。

1 项目基础协议

放弃模型原生函数调用接口,依靠约定文本格式做调用标识,程序端解析文本完成工具触发,实现等效 Agent 工具调用能力。

1.1 应答分支规则

  1. 无需调用工具:直接输出最终答案,不出现指定格式字段
  2. 需要调用工具:严格遵循固定三段式格式输出,字段顺序不可调换

1.2 标准输出格式

Thought:思考判断内容 Action:工具标识名 Action Input:工具传入参数

1.3 工具名册与使用规范

工具标识功能用途入参要求
calculator数学运算计算填写完整数学表达式
time_query获取当前系统时间无参数,填空即可
doc_search本地文档关键词检索填写检索关键词

1.4 格式约束细则

  1. 字段名称固定大小写、文字不可修改删减
  2. 思考内容简洁说明调用工具的原因
  3. 参数严格匹配对应工具格式,不额外附加多余描述

2 结构化约束 System Prompt

通过提示词强制约束模型输出范式、决策逻辑与工具使用规则,替代原生 Function Call 接口,让模型按约定格式产出可解析调用指令。

2.1 完整 Prompt 文案

你是结构化智能Agent,无法使用模型原生函数调用能力,仅按既定格式完成交互作答。 可用工具列表:1.calculator:执行数学运算,入参填写标准数学表达式2.time_query:查询当前系统时间,无需传入参数3.doc_search:检索本地文档内容,入参填写检索关键词 作答规则:1.简单问题无需调用工具,直接给出最终答案即可2.涉及计算、查时间、查文档的问题,必须严格按下方固定格式输出,不得增减内容、更改字段顺序 标准调用格式: Thought:简述调用工具的原因 Action:填写对应工具标识 Action Input:填写对应所需参数 参考示例: 示例1调用计算 Thought:需要计算数值结果,调用计算器工具 Action:calculator Action Input:12+36*2示例2查询时间 Thought:需要获取当前时间,调用时间查询工具 Action:time_query Action Input:示例3文档检索 Thought:需要查找相关文档信息,调用文档检索工具 Action:doc_search Action Input:项目开发规范

2.2 实操要点

  • 文案明确区分直接作答、工具调用两种场景
  • 绑定前期约定的工具名与入参规范,保证前后统一
  • 附上实操样例,降低模型格式出错概率

3 项目基础代码结构

采用分层模块化架构,拆分规则、工具、解析、调度模块,降低耦合,便于后续迭代扩展。

3.1 规划目录文件结构

agent_project/├── main.py# 程序入口、对话主逻辑├── tools.py# 计算器/时间/文档检索工具函数└── parser.py# 模型输出格式解析逻辑

3.2 初始化各基础文件

本次基础功能无需额外第三方库,仅使用 Python 内置模块即可开发,无需额外安装包。

简单问题:文字释义、词语理解这类属于模型自身知识库内容,不属于原生函数调用,无需动用工具,直接作答即可。

内置知识库 vs 联网搜索 边界总结
  • 内置知识库(不触发 invoke,低消耗)

    • 模型训练时录入的存量知识,本地直接推理作答适用:词语释义、常识典故、基础理论、历史固定内容、文本分析、常规问答
  • 联网搜索 / 外部工具(触发 invoke,额外耗资源)

    • 向外请求外部数据、实时内容、本地文件、运算服务适用:实时时间、最新资讯、动态数据、数学计算、文档查询、当下变动信息
  • 核心分界

    • 信息固定不变→用内置知识
    • 信息实时可变 / 外部独有→走调用检索

4 自定义工具函数

工具单独封装成独立单元,统一输入输出形式,和调度逻辑拆分,改动互不影响。

4.1 明确文件与整体思路

  • 操作文件:tools.py
  • 整体规划:分别编写三个工具方法,最后用字典建立工具名和方法的对应关系

4.2 逐个梳理工具开发要点

  • 计算器工具
    • 接收参数:数学表达式字符串
    • 核心逻辑:解析表达式算出结果
    • 容错处理:捕获计算出错的情况,返回异常提示
  • 时间查询工具
    • 接收参数:无实际有效参数
    • 核心逻辑:读取系统当前时间,规范日期时间展示格式
    • 返回内容:格式化后的时间文本
  • 本地文档检索工具
    • 接收参数:检索关键词
    • 核心逻辑:内置模拟文档数据,根据关键词匹配内容
    • 判定分支:匹配到则返回对应内容,无匹配则给出未查询到提示

4.3 构建工具映射关系

定义映射容器,把之前约定的 action 标识名,一一对应绑定到各自工具方法,后续调度时直接通过名称就能调用对应功能。

# 工具映射表TOOL_MAP={"calculator":compute,"time_query":get_time,"doc_search":search_document}

5 文本格式解析器

拆分模型返回文本,提取 Thought、Action、Input 三段内容,为后续工具调度提供有效数据。

5.1 核心思路

  1. 按固定字段标识切割文本
  2. 分别取出思考内容、工具名、入参
  3. 校验字段完整性,异常则判定无需调用工具

5.2 关键操作要点

  1. 匹配Thought:、Action:、Action Input:前缀拆分内容
  2. 去除首尾多余空格换行,规整数据
  3. 解析成功返回三段数据,解析失败返回空标识

6 工具路由调度器

承接解析后的指令,匹配对应工具函数,完成调用并返回执行结果。

执行步骤

  1. 调用解析器,拆分出思考内容、工具标识、传入参数
  2. 判断工具标识是否为空,无调用指令则仅返回思考信息
  3. 检索工具映射表,校验当前工具是否合法可用
  4. 匹配到对应工具函数,传入参数执行运算查询
  5. 汇总思考过程与工具执行结果,统一对外输出

标准格式测试输入文本

Thought:查询项目相关说明 Action:doc_search Action Input:项目介绍

核心代码

fromparserimportparserfromtoolsimportTOOL_MAPif__name__=='__main__':test_input="""Thought: 查询项目相关说明 Action: doc_search Action Input: 项目介绍"""# 调用解析器,拆分出思考内容、工具标识、传入参数input_parser=parser(test_input)print(input_parser)res=''# 判断工具标识是否为空,无调用指令则仅返回思考信息ifinput_parser['action']=='':res+=f"thought:{input_parser['thought']}"else:# 检索工具映射表,校验当前工具是否合法可用ifinput_parser['action']notinTOOL_MAP:print('当前工具不可用')else:# 匹配到对应工具函数,传入参数执行运算查询tool=TOOL_MAP[input_parser['action']]# 汇总思考过程与工具执行结果,统一对外输出output=tool(input_parser['action_input'])res+=f"thought:{input_parser['thought']}\n output:{output}"print(res)

运行结果

{'thought':'查询项目相关说明','action':'doc_search','action_input':'项目介绍'}thought:查询项目相关说明 output:这是一个无FunctionCall的结构化Agent

7 单轮 Agent 调用链路

完整流转:用户提问 → 模型推理生成结构化指令 → 解析拆解指令 → 路由匹配工具执行 → 整合结果反馈。

执行步骤

  1. 定义接收用户问题的入口
  2. 编写模拟模型逻辑,依据问题内容,产出规范格式的思考、动作、参数文本
  3. 调用原有解析模块,拆分出思考内容、工具标识、入参
  4. 走工具调度逻辑,判断是否调用工具并执行
  5. 拼接信息,输出最终答复

核心代码

(先用 mock 模拟输出,现阶段只模拟推理结果格式,暂不接入真实大模型接口)

fromparserimportparserfromtoolsimportTOOL_MAPdefinvoke(input):print(input)# 编写模拟模型逻辑,依据问题内容,产出规范格式的思考、动作、参数文本ifinput.find("计算")!=-1:test_input="""Thought: 1+1结果是什么 Action: calculator Action Input: 1+1"""elifinput.find("查询")!=-1:test_input="""Thought: 查询项目相关说明 Action: doc_search Action Input: 项目介绍"""elifinput.find("时间")!=-1:test_input="""Thought: 现在是什么时间 Action: time_query Action Input: """returntest_inputif__name__=='__main__':# 定义接收用户问题的入口llm_output=invoke("现在是什么时间")# 调用解析器,拆分出思考内容、工具标识、传入参数input_parser=parser(llm_output)res=''# 判断工具标识是否为空,无调用指令则仅返回思考信息ifinput_parser['action']=='':res+=f"thought:{input_parser['thought']}"else:# 检索工具映射表,校验当前工具是否合法可用ifinput_parser['action']notinTOOL_MAP:print('当前工具不可用')else:# 匹配到对应工具函数,传入参数执行运算查询tool=TOOL_MAP[input_parser['action']]# 汇总思考过程与工具执行结果,统一对外输出output=tool(input_parser['action_input'])res+=f"thought:{input_parser['thought']}\n output:{output}"print(res)

8 ReAct 多轮思考闭环

8.1 ReAct

ReAct = Reason(推理思考)+ Act(行动调用工具)是 Agent 经典迭代框架,边思考边行动,循环往复解决问题。

8.2 核心运作流程

  1. 思考(Reason)
    • 模型分析问题 + 已有信息,判断是否需要调用工具、用什么工具
    • → 对应你代码里的 invoke 函数,生成结构化指令
  2. 行动(Act)
    • 解析指令 → 匹配工具 → 执行函数 → 拿到结果
    • → 对应你的 parser + 工具调度逻辑
  3. 复盘(反馈)
    • 把工具执行结果回传给模型,让模型重新判断问题是否解决
  4. 循环(迭代)
    • 未解决 → 继续思考 + 调用工具
    • 已解决 → 停止循环,给出最终答案

核心规则

工具结果回传给模型,循环判断是否继续调用工具,直到问题办结。

8.3 实操分步思路

  1. 定义对话上下文变量
    • 用来存放用户问题、每一轮的思考、工具执行结果,持续传给模型
  2. 用循环包裹单轮执行逻辑
    • 让 Agent 可以自动重复:思考→行动→复盘,而不是只跑一次
  3. 每轮结束拼接上下文
    • 把本轮的思考 + 工具结果追加到上下文里,给下一轮模型使用
  4. 模型根据上下文决策
    • 读取历史信息,继续生成新指令,或判断任务完成
  5. 设置终止条件
    • 当模型输出空工具(action 为空)时,结束循环,输出最终回答

流程图

8.4 核心代码

fromparserimportparserfromtoolsimportTOOL_MAPdefinvoke(input):print(input)# 编写模拟模型逻辑,依据问题内容,产出规范格式的思考、动作、参数文本ifinput.find("计算")!=-1:test_input="""Thought: 1+1结果是什么 Action: calculator Action Input: 1+1"""elifinput.find("查询")!=-1:test_input="""Thought: 查询项目相关说明 Action: doc_search Action Input: 项目介绍"""elifinput.find("时间")!=-1:test_input="""Thought: 现在是什么时间 Action: time_query Action Input: """else:test_input="""Thought: 问题已解决 Action: Action Input:"""returntest_inputif__name__=='__main__':# 对话上下文context={"user_query":"","history":[]}# 思考:义接收用户问题的入口llm_output=invoke("现在是什么时间")context['user_query']='现在是什么时间'whileTrue:# 调用解析器,拆分出思考内容、工具标识、传入参数input_parser=parser(llm_output)# 当 action 为空时退出循环ifinput_parser['action']=='':breakres=''# 检索工具映射表,校验当前工具是否合法可用ifinput_parser['action']notinTOOL_MAP:print('当前工具不可用')break# 跳出循环,结束Agentelse:# 行动:匹配到对应工具函数,传入参数执行运算查询tool=TOOL_MAP[input_parser['action']]# 汇总思考过程与工具执行结果,统一对外输出output=tool(input_parser['action_input'])res+=f"thought:{input_parser['thought']}\n output:{output}"context['history'].append(res)print('---')print(context)# 复盘# 拼接上下文:用户问题 + 历史结果context_str=f"用户问题:{context['user_query']},历史结果:{str(context['history'])}"llm_output=invoke(context_str)

运行结果
(局部)

9 全场景测试 + 异常兼容优化

9.1 测试场景清单

  • 常规计算:帮我计算 1+1
  • 资料查询:帮我查询项目介绍
  • 时间查询:现在是什么时间
  • 无需工具闲聊:你好呀
  • 无效工具请求:帮我查询天气

9.2 代码优化要点

  • 问题抽取成变量,方便切换测试
  • 增加异常捕获,规避执行报错
  • 输出规整最终总结答复

9.3 验证标准

  • 合法请求正常调用工具、循环迭代后自动收尾
  • 无效工具、程序报错均可稳妥终止,不会死循环
  • 各类意图场景都能按逻辑分支正确响应

项目6 Function Call 智能工具助手

项目核心功能

  • 实现 3 个工具
    • 查天气工具
    • 查当前时间工具
    • 简单知识库检索工具
  • 自动调用工具
    • 用户问问题 → 模型自己判断要不要调用工具、调用哪个、传什么参数
  • 自定义解析器
    • 自己写解析函数,控制 Agent 什么时候停止思考、停止调用工具
  • 最后必须输出结构化 JSON
    • 不管中间调用多少次工具,最终回答强制输出标准 JSON,不能随便说话

Function Call

核心本质就是大模型主动调用外部工具。

核心逻辑

  • 模型本身知识有边界、没法实时数据、没法运算检索,就靠 Function Call 向外求助
  • 模型不再只输出文本,而是生成规范的工具调用指令,包含工具名、入参
  • 程序解析指令,执行对应工具拿到结果,再回传给模型
    模型结合工具返回内容,继续推理或是给出最终答复
  • 项目里的查天气、时间、知识库检索,全都是靠这套机制实现调度

开发步骤

  • 阶段 1:环境准备 + 基础配置
    • 安装必要依赖(langchain、langchain-openai 等)
    • 配置大模型(GPT / 通义千问 / 文心一言 都行)
  • 阶段 2:编写 3 个自定义工具
    • 写一个 “查天气” 工具(简单模拟返回)
    • 写一个 “查当前时间” 工具
    • 写一个 “知识库检索” 工具(模拟本地知识)
  • 阶段 3:学习并使用 bind_tools
    • 把工具绑定给大模型
    • 理解 Function Call 原理:模型什么时候决定调用工具
  • 阶段 4:搭建 AgentExecutor 执行器
    • 搭建 Agent 核心运行流程
    • 理解:用户提问 → 思考 → 调用工具 → 获取结果 → 再思考
  • 阶段 5:编写自定义解析器
    • 自己写 parse 函数
    • 控制:什么时候停止调用工具、进入最终回答
  • 阶段 6:强制输出 JSON 格式(Response 伪装)
    • 让模型最后必须调用 Response 工具
    • 输出固定结构 JSON,而不是自然语言
  • 阶段 7:完整测试
    • 测试各种问题:
      • 只需要查时间
      • 需要查天气
      • 需要查知识库
      • 混合问题
    • 看 Agent 能不能自动调度工具 + 最后输出 JSON

1 环境准备 & 基础配置

  1. 先引入环境变量、模型、工具相关基础模块
  2. 读取密钥接口地址,实例化大模型,温度设 0 保证推理稳定

2 自定义工具

LangChain 自定义工具的固定规则

  • 用 @tool 装饰器修饰一个函数
  • 函数名 = 工具名
  • 函数文档字符串(注释)= 给大模型看的工具说明(非常重要)
  • 函数参数 = 工具需要的入参
  • 函数返回值 = 工具执行结果

核心代码

fromdatetimeimportdatetimefromlangchain_core.toolsimporttool@tooldefget_current_time():returndatetime.now().strftime("%Y-%m-%d %H:%M:%S")@tooldefget_weather(city):returnf"{city}市 晴天,25℃"documents={"项目介绍":"这是一个无FunctionCall的结构化Agent","工具列表":"计算器、时间查询、文档检索","使用规则":"必须按指定格式输出调用指令"}@tooldefknowledge_base_search(query):ifqueryindocuments:returndocuments[query]else:return"未找到相关文档"

3 bind_tools

什么是 bind_tools

  • 将自定义的工具 “告诉” 大模型让模型知道:这里有几个工具可以用

需要做的事情

  • 把你定义的 3 个工具放进一个列表
  • 用模型的 .bind_tools() 方法,把这个列表传进去
  • 得到一个绑定了工具的新模型对象

规则

  • 工具列表 = [工具 1, 工具 2, 工具 3]
  • 直接调用 chat_model.bind_tools(工具列表)
  • 赋值给一个新变量,比如 llm_with_tools

核心代码

tools=[get_current_time,get_weather,knowledge_base_search]chat_model_with_tools=chat_model.bind_tools(tools)

4 AgentExecutor 执行器

  1. 必须先创建一个 Agent:create_tool_calling_agent

    • 绑定好工具的模型(chat_model_with_tools)
    • 工具列表(tools)
    • 一个 prompt 提示词模板(系统提示 + 用户输入)
  2. 创建 AgentExecutor —— Agent 的 “运行器”

    • 第一步创建的 agent
    • 工具列表tools
    • 可以加:verbose=True 看思考过程(强烈建议开)
  3. executor.invoke ()

    • 传入用户问题,即可自动调用工具

核心代码

fromlangchain_classic.agentsimportcreate_tool_calling_agent,AgentExecutorfromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholder chat_prompt_template=ChatPromptTemplate.from_messages([("system","你是工具助手,必须调用工具回答"),("user","{user_input}"),MessagesPlaceholder("agent_scratchpad")])agent=create_tool_calling_agent(chat_model_with_tools,tools,chat_prompt_template)executor=AgentExecutor(agent=agent,tools=tools,verbose=True)res=executor.invoke({"user_input":"南京天气如何"})print(res)

运行结果

5 自定义解析器

脱离默认 AgentExecutor 黑盒,手动解析工具调用、自主控制流程启停。

执行流程

  • 步骤 1:梳理核心依赖与前置准备
    • 现有资源:已绑定工具的模型、工具列表、提示词模板,直接复用。
    • 核心对象:模型返回结果里的 tool_calls 字段,用来判断是否要调用工具。
  • 步骤 2:实现工具匹配执行逻辑
    • 定义一个独立函数,入参设计为工具名、工具参数。
    • 遍历全局工具列表,根据工具名匹配对应工具。
    • 匹配成功就执行工具并返回结果;匹配失败返回提示文本。
  • 步骤 3:构造首轮对话上下文
    • 用提示词模板组装请求内容,传入用户问题。
    • agent_scratchpad 首轮传空列表,用来存放后续交互记录。
  • 步骤 4:自定义解析 & 流程控制(核心)
    • 调用模型得到响应结果。
    • 判断响应是否存在 tool_calls:
      • 存在:提取工具名、入参,调用上面的工具执行函数拿到结果,手动终止本轮流程。
      • 不存在:直接取模型文本内容作为最终回答,流程结束。

自定义解析器的自定义体现在:自己判断工具、自己拆字段、自己找工具、自己控制终止

核心代码

defexecute_action(res):fortoolintools:iftool.name==res.tool_calls[0]['name']:res=tool.invoke(res.tool_calls[0]['args'])returnresreturn'未找到对应的工具,请重试'chain=chat_prompt_template|chat_model_with_tools res=chain.invoke({"user_input":"我在胡言乱语啊啊啊啊啊","agent_scratchpad":[]})print(res)ifres.tool_calls:res1=execute_action(res)print(res1)else:# 直接提取文本内容,作为最终回复,流程结束。print(res.content)

运行结果

正常情况

南京市 晴天,25

异常情况

content='哈哈,听起来你是在释放压力或者玩文字游戏呢!如果你有任何问题、需要帮助,或者只是想聊点什么,我都很乐意陪你~ 😄 \n要不要试试问点有趣的、实用的,或者来点脑洞大开的问题?'additional_kwargs={}response_metadata={'finish_reason':'stop','request_id':'c75a6e27-08dc-9e7b-8461-c769b09fd5b6','token_usage':{'input_tokens':258,'output_tokens':53,'total_tokens':311,'prompt_tokens_details':{'cached_tokens':0}}}id='lc_run--019e64d3-f637-7820-b912-8f95b0aeb04f'tool_calls=[]invalid_tool_calls=[]哈哈,听起来你是在释放压力或者玩文字游戏呢!如果你有任何问题、需要帮助,或者只是想聊点什么,我都很乐意陪你~ 😄 要不要试试问点有趣的、实用的,或者来点脑洞大开的问题?

6 强制结构化输出

本节主要内容为:约束模型输出格式 + 自定义解析 JSON 内容。

提示词修改为

chat_prompt_template=ChatPromptTemplate.from_messages([("system","你是工具助手,必须调用工具回答。只输出 JSON,不要说任何多余的话!。如果是纯文本信息,那么回复的内容有type(值为text)和content(值为回答的内容)\n""属性,如果是工具调用相关,那么是type(值为tool)和tool_name(要调用的工具名称)和 args(工具函数的入参)"),("user","{user_input}"),MessagesPlaceholder("agent_scratchpad")])

chat_model不再需要绑定tools。在上述提示词模板下,输出如下。

content='{"type": "tool", "tool_name": "get_weather", "args": {"city": "南京"}}'additional_kwargs={}response_metadata={'finish_reason':'stop','request_id':'7838f54d-ec09-9226-922e-961fc962beb1','token_usage':{'input_tokens':96,'output_tokens':23,'total_tokens':119,'prompt_tokens_details':{'cached_tokens':0}}}id='lc_run--019e64e6-1126-7210-8933-0a5d91a01577'tool_calls=[]invalid_tool_calls=[]

对输出进行解析,修改解析器

defexecute_action(res):fortoolintools:iftool.name==res['tool_name']:res=tool.invoke(res['args'])returnresreturn'未找到对应的工具,请重试'chain=chat_prompt_template|chat_model res=chain.invoke({"user_input":"南京天气如何","agent_scratchpad":[]})print(res)content=json.loads(res.content)ifcontent['type']=='tool':res1=execute_action(content)print(res1)else:# 直接提取文本内容,作为最终回复,流程结束。print(content)

运行结果

南京市 晴天,25

本节目的

  • 在不使用模型原生工具调用(不 bind_tools)的前提下
  • 通过提示词强制模型输出【自定义结构化 JSON】
  • 手动解析格式、手动匹配工具、手动执行调用,最终拿到结果
http://www.rkmt.cn/news/1411900.html

相关文章:

  • 从Cocos到App Store:为你的iOS游戏集成AdMob广告并搞定ATT授权与GDPR合规
  • 【IEEE出版,有ISBN号,快速稳定检索,四川大学主办,高届数会议,历史优秀,往届均已实现EI、Scopus双检索,设评优环节】第九届计算机信息科学与应用技术国际学术会议(CISAT 2026)
  • 53.Python 打造智能刷机系统,完美解决批量刷机、固件损坏、手动报错问题
  • STM32 C++调试新思路:手把手教你用std::cout替代printf输出日志到网络调试助手
  • RISC-V性能分析工具链优化与实战方案
  • 别再乱用train_test_split了!用sklearn的KFold和StratifiedKFold让你的模型评估更靠谱
  • CoDe-R:基于LLM与专家规则的二进制代码语义恢复技术解析
  • 大规模MIMO有限反馈优化:基站中心化信道探测与序列导频设计
  • LTE小区反复退服故障处理:RRU级联组网光路闪断导致DISABLED状态的分析与解决
  • 察元AI超级智能体如何从安装离线大模型 ,不依赖外部大模型 数据不出域进行知识问答
  • 如何快速掌握SillyTavern:面向初学者的完整实践指南
  • 2026最新楚雄市黄金回收白银回收铂金回收店铺实力口碑排行榜TOP5;K金+金条+银条+首饰回收靠谱门店及联系方式推荐 - 前途无量YY
  • 老旧电视如何焕发新生?这款Android原生直播软件让安卓4.x设备重获高清直播能力
  • 用Python和Pygame从零实现Boids鸟群算法:一个游戏开发者的视角
  • 2026最新东兴市黄金回收白银回收铂金回收店铺实力口碑排行榜TOP5;K金+金条+银条+首饰回收靠谱门店及联系方式推荐 - 前途无量YY
  • Layuimini:无限级菜单系统的架构设计与企业级实现路径
  • 音乐格式解放:当NCM加密遇到Go语言多线程转换
  • 别再用通用Prompt写冥想文案!神经语言学家实测:3个微调参数让GPT生成内容通过正念教师资质审核
  • 猫抓:当浏览器成为你的个人视频档案馆
  • leetcode思路-回溯最后一节(131.分割回文串、51.N皇后)
  • 2026最新达州市黄金回收白银回收铂金回收店铺实力口碑排行榜TOP5;K金+金条+银条+首饰回收靠谱门店及联系方式推荐 - 前途无量YY
  • 2026最新都江堰市黄金回收白银回收铂金回收店铺实力口碑排行榜TOP5;K金+金条+银条+首饰回收靠谱门店及联系方式推荐 - 前途无量YY
  • 解锁Windows远程桌面多用户限制:RDPWrap完整部署与优化指南
  • 2026最新的北京电动车运输公司怎么选?推荐一下 哪家好 - 奔跑123
  • 别再只用TB6612了!用DRV8833给Arduino智能小车做电机驱动,实测对比与避坑指南
  • 如何快速解决编码乱码问题:终极跨平台GBK转UTF-8解决方案
  • 5个核心功能解锁专业级VRM创作:Blender插件全面指南
  • 3分钟掌握猫抓:浏览器资源嗅探的终极解决方案
  • 高价回收支付宝红包的秘诀:你需要知道这些平台! - 团团收购物卡回收
  • 2026最新大理市黄金回收白银回收铂金回收店铺实力口碑排行榜TOP5;K金+金条+银条+首饰回收靠谱门店及联系方式推荐 - 前途无量YY