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

[AI Agent 01]对话记忆、Agent 循环、Function Calling

代码是AI写的,用的CC接入DS-v4-pro,代码功能包含:对话记忆、Agent 循环、Function Calling

本篇文章仅作为个人学习笔记记录分享

完整代码如下:

""" Agent 初体验 —— 让 AI 能运行 Python 代码 =========================================== 核心概念 Function Calling: 1. 告诉 AI "你有一个工具可以用" 2. AI 判断需要用工具时,会"请求调用"它 3. 我们帮 AI 执行工具,把结果返回 4. AI 看到结果后,组织语言回答用户 这整个循环就叫 Agent Loop(智能体循环) """ import sys import os sys.stdout.reconfigure(encoding="utf-8") from openai import OpenAI from dotenv import load_dotenv import json import io load_dotenv() client = OpenAI( api_key=os.getenv("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com", ) # ============ 第1步:定义一个工具(函数) ============ # 这个函数真的会执行 Python 代码,并把结果返回 def run_python_code(code: str) -> str: """执行 Python 代码并返回结果""" try: # 用 StringIO 拦截 print 的输出 old_stdout = sys.stdout captured = io.StringIO() sys.stdout = captured local_vars = {} exec(code, {}, local_vars) sys.stdout = old_stdout # 恢复标准输出 output = captured.getvalue().strip() if output: return output if local_vars: return str(list(local_vars.values())[-1]) return "代码执行完成(无输出)" except Exception as e: sys.stdout = old_stdout # 出错也要恢复! return f"执行出错:{e}" # ============ 第2步:把工具"注册"给 DeepSeek ============ # 用 JSON 格式描述这个工具是干嘛的、接受什么参数 tools = [ { "type": "function", "function": { "name": "run_python_code", "description": "执行一段 Python 代码并返回结果。当你需要计算、处理数据时使用此工具。", "parameters": { "type": "object", "properties": { "code": { "type": "string", "description": "要执行的 Python 代码,比如 'sum(range(1, 101))'", } }, "required": ["code"], }, }, } ] # 工具名 → 真实函数的映射表 tool_map = {"run_python_code": run_python_code} # ============ 第3步:Agent 主循环 ============ messages = [ {"role": "system", "content": "你是一个能执行Python代码的助手。遇到需要计算的问题时,调用 run_python_code 工具。最后用中文回答用户。"}, ] print("=" * 50) print("AI Agent 聊天室 —— 我能帮你算数学、处理数据!") print("试试说:'1加到100是多少' 或 '帮我算 3的100次方'") print("输入 'quit' 退出") print("=" * 50) while True: user_input = input("\n你: ") if user_input.lower() == "quit": print("再见!") break messages.append({"role": "user", "content": user_input}) # 第1次调用:AI 可能选择直接回答,也可能选择调用工具 response = client.chat.completions.create( model="deepseek-chat", messages=messages, tools=tools, ) reply = response.choices[0].message # ---------- 关键:检查 AI 是否想调用工具 ---------- if reply.tool_calls: # AI 说"我想用工具!" for tool_call in reply.tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) print(f" [Agent 调用工具: {func_name}({func_args})]") # 真正执行这个工具函数 tool_result = tool_map[func_name](**func_args) print(f" [工具返回: {tool_result[:60]}...]") # 把工具调用和结果都加入记忆 messages.append( { "role": "assistant", "content": reply.content or "", "tool_calls": [ { "id": tool_call.id, "type": "function", "function": { "name": func_name, "arguments": tool_call.function.arguments, }, } ], } ) messages.append( { "role": "tool", "tool_call_id": tool_call.id, "content": tool_result, } ) # 第2次调用:把工具结果发给 AI,让它总结 response = client.chat.completions.create( model="deepseek-chat", messages=messages, ) reply = response.choices[0].message # ---------- 打印最终回复 ---------- print(f"AI: {reply.content}") # 把 AI 的最终回复记入历史 messages.append({"role": "assistant", "content": reply.content})

关于我不会的东西:

1.与内置标准库模块sysos对接,后续可以借用其中功能

import sys import os

2.reconfigure用于运行时更改参数

(形参=实参),函数定义时可以有形参可以无形参,def 函数 (形参=实参,形参=实参):

若定义时def 函数 (形参,形参):则调用时可以函数(实参,实参)实参与形参会自动对应

sys.stdout.reconfigure(encoding="utf-8")

3.从【包名】中调用【类名/函数名】

from openai import OpenAI from dotenv import load_dotenv

4.OpenAI(...)调用实例化,括号里可以传递参数,这些参数会传给类的 构造方法 __init__,用来初始化新创建的对象。

构造方法def __init__(self,name,age):

同一个可以创建出无数个独立的实例,每个实例可以有自己的数据

os.getenv()读取环境变量

client = OpenAI( api_key=os.getenv("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com", )

5.列表[ ],记录对话的顺序

其中的元素为字典{ },由键值对构成,形式相当于“标签:内容”

role :system系统/用户user/助手assistant(可帮助辨认身份)

content :具体说的话(可记忆对应发言)

messages=[ {"role": "system", "content": "你是一个友好的助手,喜欢用简洁的方式回答问题。"}, {"role": "user", "content": "你好!请用一句话介绍你自己。"}, ]

6.[0]的意思是把列表里的第1个选项拿出来

response.choices[0].message.content

7..lower()方法将字符串中的所有字母都变成小写

if user_input.lower() == "quit":

8.client.chat.completions.create()链式调用

messages=messages参数名=值,作用是把整个对话历史列表传给 AI,等号左边的messages是函数内部定义好的参数名,等号右边的messages是在程序里定义的变量,如果不想混淆也可以写成messages=conversation_history

response = client.chat.completions.create( model="deepseek-chat", messages=messages, )

9.def定义函数,run_python_code表示函数名,code: str表示参数名为 code ,同时类型是字符串,-> str表示返回值类型是字符串

def run_python_code(code: str) -> str:

10.old_stdout保存输出到屏幕,captured创建一个内存中的字符串缓冲区

sys.stdout = captured把输出重定向到缓冲区,sys.stdout代表“标准输出流”,默认就是终端

io.StringIO()是一个伪装成文件的内存字符串,创建一个内存中的文件对象,行为类似于一个文本文件,但数据存储在内存字符串中,有.write()方法写入字符串,以及.getvalue()方法获取里面全部内容

old_stdout = sys.stdout captured = io.StringIO() sys.stdout = captured

11.try-except尝试执行代码,如果出错就捕获异常

try: except Exception as e: sys.stdout = old_stdout return f"执行出错:{e}"

12.exec(code, globals, locals)

exec()是 Python 的内置函数,它接收一个字符串,并把这个字符串当作 Python 代码来执行

globals参数 {}是空字典。表示执行这段代码时,全局作用域是空的,这意味着代码中不能访问外部的任何全局变量,也不能修改外部的全局变量

local_vars是一个空字典,但在 exec 执行过程中,代码中定义的所有局部变量都会自动存储到这个字典中

local_vars = {} exec(code, {}, local_vars)

注意区别:

captured.getvalue()获取print的输出
local_vars字典获取代码执行后产生的所有局部变量

13."parameters": {...}本质是字典,但是是JSON Schema,格式是固定的,键是固定的

"type": "object"意味着这个参数的类型是object(对象),而在 JSON 里,对象就是花括号括起来的一组键值对

"parameters": { "type": "object", "properties": { "code": { "type": "string", "description": "要执行的 Python 代码,比如 'sum(range(1, 101))'", } }, "required": ["code"], }

14.创建了从函数名到实际函数的映射关系,在键值对中,键"run_python_code"是字符串仅代表名称,值run_python_code没有双引号同时没有括号,代表并不在调用函数,仅代表函数本身

tool_map = {"run_python_code": run_python_code}

15.tool_call.function.name是字符串,对应之前在tools 列表中定义的工具名tool_call.function.arguments是字符串,内容是 JSON 格式的参数{键: 值}
json.loads(...)把AI返回的arguments(JSON 字符串)解析成 Python 字典,即变成{键: 值},然后可以直接用字典键来访问参数值

for tool_call in reply.tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments)

16.tool_map[func_name]取得函数对象,(**func_args)是字典解包语法,把func_args字典中的键值对传递给函数
eg:如果func_args = {"code":"print(1+2)"},则调用等价于run_python_code(code="print(1+2)")tool_result就是函数执行后的返回值

tool_result = tool_map[func_name](**func_args)
http://www.gsyq.cn/news/1499524.html

相关文章:

  • 2026年怎么降低论文AIGC率?7种高效方法必收藏!
  • 宝塔面板如何设置网站伪静态 宝塔|Nginx网站部署 伪静态配置|静态资源访问配置
  • 2026年实测有效:4个指令+3个技巧助你把论文AI率从50%降到10%
  • 郑州人注意!闲置迪奥包别乱卖,看完少踩坑 - 奢侈品回收评测
  • 三、SCI熟词生意(一)
  • IEC 61850:GOOSE报文详细解析(下篇)
  • 2026年|知网、维普AIGC检测率差46%!同一论文AI率该信谁?必备降AI工具推荐
  • 2026标准数字时钟系统品牌排行与价格选购攻略 - 品研笔录
  • 视频水印处理三大场景总结,多款轻量化工具实测分享
  • 鸿蒙原生应用实战(二):首页开发与全局数据流设计
  • 宁波精装房石材改造指南:不砸不拆怎么提升质感(2026版) - 宁波融诚石业
  • 知识图谱 Graph Rag 方法横向对比
  • Web分布式网站架构之-Squid缓存【20260608】005篇-【传统代理】
  • 【UE5】雷达覆盖区域效果
  • 2026年 黑龙江铝塑铝门窗/哈尔滨保暖铝塑铝门窗推荐榜:高密封、抗老化、高性价比家装与老旧小区改造优选 - 品牌发掘
  • 闲置多年奢侈品腕表,2026无锡手表回收如何养护价值更高 - 奢侈品回收评测
  • SQL/NoSQL数据库为何成为TVA的记忆系统(7)
  • 2026年苏州定制家具厂家推荐榜:酒店餐饮、适老化、医养机构与养老院圆角防撞星级配套家具精选 - 品牌发掘
  • 数据分析进阶——经营分析指标字典
  • Web分布式网站架构之-Squid缓存【20260609】squid配置文件详解002篇
  • 伺服电机仿真(4):PMSM在d-q旋转坐标系下的状态方程与等效电路
  • 2026年 重庆广告门/电梯广告门/广告道闸推荐榜:小区与写字楼高性价比之选 - 品牌发掘
  • 【Prometheus Operator 监控 K8S集群的Calico 与 Ingress-Nginx 组件】
  • 2026LV 名牌包包回收,无锡权威门店老花经典款回收实测 - 奢侈品回收评测
  • 2026拼多多AI客服深度测评:性价比与效率兼得的品牌推荐 - 品研笔录
  • 宁波各区石材装修预算参考:鄞州/海曙/江北/北仑(2026版) - 宁波融诚石业
  • 【人工智能学习260609】可以直接复制用的✅ 测试用例生成 Prompt 模板 ✅ Bug分析模板 ✅ 日志分析模板模板
  • AI Agent Harness Engineering 作为科研伙伴的新角色
  • C++(贪心算法一)
  • 2026固化剂地坪选购全攻略:贵州厂家实力排行与避坑要点 - 品研笔录