Skip to content

sunq821-byte/AI_Agent_Python

Repository files navigation

AI 智能体开发教学项目

这是一个基于 Python 的 AI 智能体开发教学项目,包含多个实践练习,帮助学习者掌握 AI 智能体的开发技能。

项目结构

code_AI_fin/
├── venv/                        # Python 虚拟环境
├── .gitignore                   # Git 排除配置
├── .env                         # 环境变量配置(需自行创建)
├── env.example                  # 环境变量模板
├── README.md                    # 项目说明文档
├── practice01/                  # 练习1:基础 LLM 调用
│   └── llm_client.py            # 使用标准 HTTP 库调用 LLM
├── practice02/                  # 练习2:工具调用
│   └── llm_tool_client.py       # 支持文件操作和网络访问工具调用
└── practice03/                  # 练习3:聊天记录管理
    ├── llm_summary_client.py    # 新代码1:聊天记录智能压缩与总结
    └── llm_knowledge_client.py  # 新代码2:5W记忆提取 + 历史检索
└── practice04/                  # 练习4:外部知识库集成
    └── llm_knowledge_client.py  # 集成AnythingLLM文档仓库查询
├── practice05/                  # 练习5:技能系统(Skill System)
│   └── llm_knowledge_client.py  # 技能列表读取 + 技能加载 + 按技能指令执行
├── practice06/                  # 练习6:链式工具调用(Chained Tool Calls)
│   └── llm_knowledge_client.py  # 链式调用上下文管理 + 多步自主决策执行
├── .agents/                     # 技能定义目录
    └── skills/                  # 技能集合
        └── notice/              # 通知撰写技能
            └── SKILL.md         # 技能定义文件(YAML front matter + 正文)

环境要求

  • Python 3.11+
  • OpenAI 兼容的 LLM API(如 OpenAI、LM Studio、Ollama 等)

快速开始

1. 激活虚拟环境

# Windows
venv\Scripts\activate

# 退出虚拟环境
deactivate

2. 配置环境变量

复制环境变量模板并填写您的 LLM 配置:

copy env.example .env

编辑 .env 文件:

LLM_BASE_URL=http://127.0.0.1:1234/v1
LLM_MODEL=qwen3.5-9b
LLM_API_KEY=your-api-key-here
MAX_TOKENS=2000
TEMPERATURE=0.7

3. 运行练习

练习1:基础 LLM 调用

python practice01/llm_client.py

功能:使用 Python 标准 HTTP 库调用 LLM,统计 Token 消耗、时间和速度。

练习2:工具调用客户端

python practice02/llm_tool_client.py

功能:增加工具调用能力,支持 list_files / rename_file / delete_file / create_file / read_file / curl_url 六类工具。

练习3 新代码1:聊天记录自动总结

python practice03/llm_summary_client.py

触发条件:对话轮数 > 5 轮,或上下文字符数 > 3000。
策略:前 70% 历史压缩为摘要,保留后 30% 原文。支持流式输出。

练习3 新代码2:5W记忆提取 + 历史检索

python practice03/llm_knowledge_client.py

新增两大功能: ① 每 5 轮自动提取 5W 关键信息,追加写入 D:\chat-log\log.txt ② 检测到 /search 指令或搜索意图时,注入日志知识库进行检索问答

练习4:集成 AnythingLLM 文档仓库查询

python practice04/llm_knowledge_client.py

在 practice03 基础上新增 AnythingLLM 文档仓库查询工具,用户提到"文档仓库"、"文件仓库"、"仓库"时自动触发。

练习5:技能系统(Skill System)

python practice05/llm_knowledge_client.py

在 practice04 基础上新增动态技能系统。程序启动时自动扫描 .agents/skills/ 目录下所有技能,将技能列表注入 system prompt。当用户请求匹配某技能时,LLM 自动调用 load_skill_content 加载技能指令,然后严格按照指令执行。

内置技能:

技能名 说明 触发条件
notice 部门通知撰写 用户要求写通知/发通知/润色通知

技能文件格式(.agents/skills/{skill_name}/SKILL.md):

---
name: skill_name
description: 技能描述,用于 LLM 判断是否需要加载此技能
---

### 技能正文(LLM 加载后按此指令执行)
...

练习6:链式工具调用(Chained Tool Calls)

python practice06/llm_knowledge_client.py

在 practice05 基础上新增链式工具调用能力。用户输入 /chain <请求> 进入链式调用模式,LLM 自主规划多步骤任务,前一步工具的输出作为后一步的输入,实现复杂的端到端自动化工作流。

链式调用模式使用方式:

You: /chain 查找 practice05 目录下所有包含'def'关键词的文件,并总结主要内容
[链式调用模式] 请求: 查找 practice05 目录下所有包含'def'关键词的文件...
──────────────────────────────────────────────────
  [链式调用] 迭代 1/10
──────────────────────────────────────────────────
  [决策] 调用工具: search_files_content
  [参数] {"directory": "...", "keyword": "def"}
  [结果] ...
──────────────────────────────────────────────────
  [链式调用] 迭代 2/10
──────────────────────────────────────────────────
  [决策] 调用工具: read_file
  [参数] {"directory": "...", "file_name": "llm_knowledge_client.py"}
  [结果] ...
──────────────────────────────────────────────────
  [链式调用] 迭代 3/10
──────────────────────────────────────────────────
  [完成] 任务结束
  [最终回答] ...
  (共 3 步, 耗时 12.34s)
[链式调用完成] 总步数: 3, 耗时: 12.34s

练习说明

Practice 01:基础 LLM 调用

  • 使用 Python 标准库 http.client 调用 OpenAI 兼容 API
  • 读取 .env 配置文件
  • 统计 Token 消耗、响应时间、处理速度

Practice 02:工具调用客户端

  • 在终端聊天客户端基础上增加工具调用能力
  • 支持文件操作:列出文件、创建文件、读取文件、修改文件名、删除文件
  • 支持网络访问:通过 HTTP/HTTPS 获取网页内容
  • LLM 自动判断是否需要调用工具

Practice 03 新代码1:聊天记录自动总结与压缩 ⭐

核心教学目标:解决 LLM 上下文窗口有限的问题,通过智能压缩历史记录延长有效对话。

触发机制

条件 阈值 说明
对话轮数 > 5 轮 user+assistant 算一轮
上下文长度 > 3000 字符 仅统计非 system 消息

压缩策略

历史消息(排除 system):
[msg1  msg2  msg3  ...  msg7  msg8  msg9  msg10]
 |_______前 70% 压缩为摘要___|  |_后 30% 保留_|

重建后:
[system_原始, system_摘要, msg8, msg9, msg10]

关键函数

函数 功能
should_compress(history) 检测是否触发压缩,返回 (bool, 原因)
compress_history(...) 执行压缩:切分 → 调 LLM 总结 → 重建历史
_build_compress_prompt(msgs) 构造总结提示词
call_llm_stream(...) 流式调用 LLM 并实时打印
call_llm(...) 非流式调用 LLM(用于总结/提取任务)

Practice 03 新代码2:5W记忆提取 + 历史检索 ⭐⭐

核心教学目标:让 Agent 具备长期记忆能力——主动提取关键知识并在需要时精准检索。

功能1:5W 关键信息自动提取

每隔 5 轮对话,自动触发 LLM 按 5W 规则提取关键信息,追加写入本地日志文件。

5W 规则

字段 含义 是否必填
Who 涉及的主体 必填
What 发生的事件/行动 必填
When 时间信息 可选
Where 地点信息 可选
Why 目的/原因 可选

日志格式(D:\chat-log\log.txt)

--------------------------------------------------
[2026-05-17 14:30:00] 关键信息提取
--------------------------------------------------
  [1]
    Who  : 用户
    What : 询问如何用Python读取文件
    Why  : 学习编程
  [2]
    Who  : 助手
    What : 介绍了 open() 函数的用法
    When : 当前对话

5W 提示词工程要点

  • 要求 LLM 严格以 JSON 数组输出,温度设为 0.1 保证格式稳定
  • 系统消息约束:「只能输出 JSON 数组,不得输出其他内容」
  • 容错机制:提取响应中的 [...] 区间,防止 LLM 输出前缀文字

关键函数

函数 功能
_build_5w_extract_prompt(msgs) 构造 5W 提取提示词(要求 JSON 数组输出)
extract_5w_info(history, ...) 调用 LLM 提取信息,容错解析 JSON
append_to_log(items, path) 追加写入日志,自动创建目录/文件
maybe_extract_and_log(...) 每 5 轮触发一次完整提取流程

功能2:历史检索 Function Call

当检测到搜索意图时,自动将 log.txt 作为知识库注入上下文,完成带记忆的 LLM 问答。

触发方式(优先级由高到低)

方式 示例 Token 消耗
/search 前缀 /search 上次说的项目 零(关键词匹配)
中文关键词 查找聊天历史 / 以前说过 零(关键词匹配)
LLM 意图识别 「你还记得我之前提到的事吗」 极少(YES/NO 约束)

搜索意图识别提示词要点

  • 系统消息:「你是意图识别助手。你只能回答 YES 或 NO」
  • 温度设为 0.0,max_tokens=5,强制最小化输出
  • 关键词检测优先,LLM 识别作为兜底

检索增强提示词结构

[system]
你是一个聊天历史检索助手。
以下是用户过往对话中提取的关键信息日志(5W格式):

<knowledge_base>
{log.txt 完整内容}
</knowledge_base>

请根据上述日志,准确回答用户的查询问题。

[user]
{用户的实际查询内容}

关键函数

函数 功能
_detect_search_intent_by_keyword(input) 基于关键词快速检测意图(零 token)
_detect_search_intent_by_llm(input, ...) LLM 意图判断(YES/NO 强约束)
read_log_file(path) 读取日志,文件不存在时返回空串
handle_search_request(input, ...) 注入知识库,执行检索流式问答

运行效果示例

LLM Knowledge Client - 5W记忆提取 + 历史检索
=======================================================
5W提取    : 每 5 轮触发一次
日志路径  : D:\chat-log\log.txt
=======================================================

You: 帮我写个冒泡排序
Assistant: (流式回复...)
--- 状态统计 ---
累计轮数: 5  |  上下文长度: 1234 字符  |  已压缩: 0 次

──────────────────────────────────────────────────────
[5W提取 @第5轮] 触发关键信息提取...
[5W提取] 共提取 2 条关键信息:
  [1] 用户 → 请求编写冒泡排序算法 | Why: 学习算法
  [2] 助手 → 提供了冒泡排序Python实现
[5W提取] 已追加写入 D:\chat-log\log.txt

You: /search 我之前让你写过什么算法?
[搜索模式] 注入知识库(386 字符),正在检索...
Assistant: 根据历史记录,您曾请求编写冒泡排序算法...

技术栈

  • Python 3.11+ - 编程语言
  • http.client - 标准 HTTP 客户端(无第三方依赖)
  • json - JSON 数据处理
  • OpenAI API 兼容协议 - LLM 接口标准
  • Server-Sent Events (SSE) - 流式响应解析

配置常量参考

常量 文件 默认值 说明
MAX_ROUNDS 两个 py 5 超过该轮数触发上下文压缩
MAX_CTX_CHARS 两个 py 3000 超过该字符数触发上下文压缩
KEEP_RATIO 两个 py 0.30 保留最近 30% 的对话原文
EXTRACT_EVERY knowledge 5 每隔多少轮触发 5W 提取
LOG_FILE_PATH knowledge D:\chat-log\log.txt 关键信息持久化路径
MAX_CHAIN_ITERATIONS practice06 10 链式调用最大迭代次数

使用 LM Studio 本地运行

  1. 下载并安装 LM Studio
  2. 在 LM Studio 中下载您喜欢的模型
  3. 启动本地服务器(默认端口 1234)
  4. 配置 .env
    LLM_BASE_URL=http://127.0.0.1:1234/v1
    LLM_MODEL=您的模型名称
    LLM_API_KEY=lm-studio
    MAX_TOKENS=2000
    TEMPERATURE=0.7

工具调用使用示例(Practice 02)

文件操作

{"tool": "list_files", "params": {"directory": "d:\\ziliao\\code_AI_fin"}}
{"tool": "create_file", "params": {"directory": "d:\\ziliao", "file_name": "test.txt", "content": "Hello"}}
{"tool": "read_file", "params": {"directory": "d:\\ziliao", "file_name": "test.txt"}}
{"tool": "rename_file", "params": {"directory": "d:\\ziliao", "old_name": "test.txt", "new_name": "new.txt"}}
{"tool": "delete_file", "params": {"directory": "d:\\ziliao", "file_name": "new.txt"}}

网络访问

{"tool": "curl_url", "params": {"url": "https://wttr.in/Chengdu"}}
{"tool": "curl_url", "params": {"url": "https://example.com"}}

文档仓库查询(Practice 04)

{"tool": "anythingllm_query", "params": {
  "message": "项目使用了哪些技术栈?",
  "api_key": "your-api-key",
  "workspace_slug": "my-workspace"
}}

Practice 04:集成 AnythingLLM 文档仓库查询 ⭐⭐

核心教学目标:让 Agent 能够查询外部知识库(AnythingLLM 文档仓库),实现"文档问答"能力。

前置条件

  1. 安装并运行 AnythingLLM(默认端口 3001)
  2. 在 AnythingLLM 中创建一个 Workspace,上传文档
  3. 在 AnythingLLM Settings > API Keys 中生成 API 密钥
  4. .env 中配置:
    ANYTHINGLLM_API_KEY=your-api-key
    ANYTHINGLLM_WORKSPACE_SLUG=your-workspace-slug

新增工具

工具名 功能 触发条件
anythingllm_query 查询 AnythingLLM 文档仓库 用户提到"文档仓库"、"文件仓库"、"仓库"

技术实现要点

要点 说明
通信方式 subprocess 调用系统 curl 命令
API 端点 POST http://localhost:3001/api/v1/workspace/{slug}/chat
认证方式 Authorization: Bearer <API_KEY>
请求体 {"message": "...", "mode": "chat"}
中文编码 subprocess.run(..., encoding="utf-8", errors="replace")
超时处理 120 秒超时保护
容错解析 支持 textResponseresponsecontent 多种响应键

运行效果示例

LLM Knowledge Client + AnythingLLM
==================================================
Model: qwen3.5-9b
Base URL: http://127.0.0.1:1234/v1
5W Extract: every 5 rounds
AnythingLLM: my-docs @ http://localhost:3001
==================================================

You: 帮我查一下文档仓库里关于API认证的说明
[调用工具中...]
[工具执行结果]
[AnythingLLM 仓库回复]
根据文档,API认证采用Bearer Token方式...

Assistant: 根据文档仓库的信息,API认证采用Bearer Token...

Practice 05:技能系统(Skill System) ⭐⭐⭐

核心教学目标:让 Agent 具备动态技能加载能力——通过读取外部技能定义文件,按需加载并严格遵循技能指令执行。

技能系统架构

用户输入 → LLM 判断是否需要技能
                ↓ 是
         调用 load_skill_content(skill_name)
                ↓
         读取 .agents/skills/{name}/SKILL.md 正文
                ↓
         注入 system prompt → LLM 按技能指令执行

核心函数

函数 功能
list_available_skills() 扫描 .agents/skills/ 子目录,解析 YAML front matter,返回技能列表
load_skill_content(skill_name) 根据技能名加载 SKILL.md 正文(front matter 之后的部分)
build_skills_prompt() 构建技能列表的 system prompt 文本
_parse_front_matter(content) 解析 YAML front matter,提取 name 和 description
_extract_yaml_field(text, field) 从 YAML 文本中提取指定字段值

技能文件规范

要素 说明
目录结构 .agents/skills/{skill_name}/SKILL.md
YAML front matter --- 包裹,包含 namedescription 字段
技能正文 front matter 之后的内容,定义技能的执行规则
添加新技能 .agents/skills/ 下新建子目录,放入 SKILL.md 即可

新增工具

工具名 功能 触发条件
load_skill_content 加载指定技能的完整指令 LLM 判断用户请求匹配某技能描述时调用

运行效果示例

LLM Knowledge Client + Skills System
==================================================
Loaded skills: ['notice']
==================================================

You: 帮我写一个关于五一劳动节放假的通知
[调用工具中...]
  [执行工具] load_skill_content
  [参数] {"skill_name": "notice"}
[技能加载] notice

Assistant: **XX部通知**
为弘扬劳动精神,保障员工合法权益...
特此通知。

You: 我是销售部的,帮我写一个关于五一劳动节放假的通知
[调用工具中...]
  [执行工具] load_skill_content
  [参数] {"skill_name": "notice"}
[技能加载] notice

Assistant: **销售部通知**
为庆祝"五一"国际劳动节,保障员工合法权益...
特此通知。

Practice 06:链式工具调用(Chained Tool Calls) ⭐⭐⭐⭐

核心教学目标:让 Agent 具备自主规划和执行多步骤任务的能力——前一个工具的输出作为后一个工具的输入,LLM 根据中间结果自主决定下一步操作。

链式调用架构

用户请求: /chain 查找文件并总结
    ↓
┌─────────────────────────────────────┐
│  ChainedCallContext(上下文管理器)   │
│  - 记录每步调用和结果                │
│  - 存储中间变量供后续步骤使用         │
│  - 设置最大迭代次数(默认 10)        │
└──────────┬──────────────────────────┘
           ↓ 循环(最多 max_iterations 次)
┌─────────────────────────────────────┐
│  build_analysis_prompt()            │
│  - 用户原始请求                      │
│  - 已执行步骤历史                    │
│  - 决策规则 + JSON 输出格式          │
└──────────┬──────────────────────────┘
           ↓
┌─────────────────────────────────────┐
│  LLM 决策                            │
│  done=true  → 返回最终回答           │
│  done=false → 调用工具,记录结果      │
└─────────────────────────────────────┘

核心类和函数

类/函数 功能
ChainedCallContext 链式调用上下文管理器,记录步骤、存储中间变量、限制最大迭代
ChainedCallContext.add_step() 记录一步工具调用或最终回答
ChainedCallContext.get_history_text() 获取已执行步骤的可读文本(供提示词使用)
ChainedCallContext.is_max_reached() 检查是否达到最大迭代次数
execute_chained_tool_call() 执行链式调用的完整流程(循环 + LLM 决策 + 工具执行)
build_analysis_prompt() 构建分析提示词(含用户请求、步骤历史、决策规则、JSON 格式)
execute_tool_by_name() 根据工具名和参数执行对应工具函数
_extract_json_from_content() 从 LLM 响应中提取 JSON(兼容纯 JSON、代码块、前缀文字)
_parse_tool_calls_response() 解析 OpenAI tool_calls 格式为统一决策格式
search_files_content() 新增工具:搜索目录下包含关键词的文件及其上下文行

LLM 决策 JSON 格式

场景 格式
任务完成 {"done": true, "answer": "最终回答内容"}
继续调用 {"done": false, "tool_call": {"name": "工具名称", "arguments": {"参数名": "参数值"}}}

新增工具

工具名 功能 参数
search_files_content 搜索目录下包含关键词的文件 directory, keyword

使用方式

在交互模式中输入 /chain <请求> 进入链式调用模式:

You: /chain 查找 practice05 目录下所有包含'def'关键词的文件,并总结这些文件的主要内容
You: /chain 读取 D:\ziliao\1.txt 和 D:\ziliao\2.txt,把两个数相加写入 result.txt
You: /chain 访问 https://www.nsu.edu.cn/HTML/news/2024/06/article_3974.html 并总结页面内容,保存到 practice07/summary.txt

链式调用流程示例(文件搜索链):

[链式调用] 迭代 1/10
  [决策] 调用工具: search_files_content
  [参数] {"directory": "practice05", "keyword": "def"}
  [结果] 文件: llm_knowledge_client.py (15处匹配)

[链式调用] 迭代 2/10
  [决策] 调用工具: read_file
  [参数] {"directory": "practice05", "file_name": "llm_knowledge_client.py"}
  [结果] Content of 'llm_knowledge_client.py': ...

[链式调用] 迭代 3/10
  [完成] 任务结束
  [最终回答] practice05 目录下共找到 1 个文件包含 'def' 关键词...
  (共 3 步, 耗时 15.23s)

错误处理与容错机制

错误类型 处理方式
LLM 响应为 None 终止链式调用,返回错误信息
JSON 解析失败(代码块/前缀文字) _extract_json_from_content() 自动提取 {...}
tool_calls 格式响应 _parse_tool_calls_response() 转换为统一决策格式
工具执行异常 try/except 捕获,返回错误信息给 LLM 继续决策
达到最大迭代次数 _build_partial_answer() 根据已有步骤生成部分回答
done=false 但无 tool_call 强制结束,返回"任务中断"提示

许可证

MIT License

贡献

欢迎提交 Issue 和 Pull Request!

About

人工智能提示课实验

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages