🚀 从零开始构建小说推荐智能体 - Coze 本地部署完整教程
适用对象 : 小白新手、开发者、AI 应用爱好者
学习目标 : 从入门到进阶,掌握使用 Coze 本地部署智能体和工作流
实战案例: 小说推荐智能体
📚 目录
- [入门篇 - 理解智能体基础](#入门篇 - 理解智能体基础)
- [进阶篇 - 构建小说推荐智能体](#进阶篇 - 构建小说推荐智能体)
- [高级篇 - 工作流编排与优化](#高级篇 - 工作流编排与优化)
- 最佳实践
- [常见问题 FAQ](#常见问题 FAQ)
入门篇 - 理解智能体基础
1.1 什么是智能体 (Agent)?
智能体是一种能够感知环境、做出决策并执行动作的 AI 系统。与传统 AI 不同,智能体具备:
- 自主性: 能够独立思考和决策
- 工具使用: 可以调用外部工具完成任务
- 记忆能力: 能够记住对话历史和上下文
- 目标导向: 围绕特定目标展开行动
类比 : 想象智能体就像一个智能助手,它能理解你的需求,使用各种工具(搜索、数据库、API),并给出专业的回答。
1.2 智能体的核心组件
┌─────────────────────────────────────────┐
│ 智能体 (Agent) │
├─────────────────────────────────────────┤
│ 📌 核心模型 (LLM) │
│ - 理解语言 │
│ - 推理决策 │
│ - 生成回复 │
├─────────────────────────────────────────┤
│ 🛠️ 工具 (Tools) │
│ - 搜索工具 │
│ - 数据库工具 │
│ - API 调用工具 │
├─────────────────────────────────────────┤
│ 💾 记忆 (Memory) │
│ - 对话历史 │
│ - 用户偏好 │
│ - 上下文信息 │
├─────────────────────────────────────────┤
│ 📝 提示词 (System Prompt) │
│ - 角色定义 │
│ - 任务说明 │
│ - 行为约束 │
└─────────────────────────────────────────┘
1.3 Coze 本地部署的优势
✅ 数据安全 : 所有数据在本地处理,不上传云端
✅ 成本低廉 : 仅需支付模型调用费用,无平台抽成
✅ 灵活定制 : 完全掌控代码,自由修改和扩展
✅ 隐私保护 : 敏感数据留在本地环境
✅ 无限可能: 支持任意第三方工具和服务集成
进阶篇 - 构建小说推荐智能体
2.1 需求分析
目标: 构建一个小说推荐智能体,能够:
- 理解用户阅读偏好
- 搜索小说信息
- 提供个性化推荐
- 记住用户历史偏好
能力评估:
| 能力 | 实现方式 | 是否需要工具 |
|---|---|---|
| 理解用户偏好 | LLM 原生能力 | ❌ |
| 搜索小说信息 | 联网搜索 | ✅ |
| 生成推荐理由 | LLM 原生能力 | ❌ |
| 对话记忆 | Memory 机制 | ❌ |
结论 : 只需要联网搜索工具,其他能力由 LLM 原生提供。
2.2 项目结构
/workspace/projects/
├── config/
│ └── agent_llm_config.json # 模型配置
├── src/
│ ├── agents/
│ │ └── agent.py # 智能体主代码
│ └── tools/
│ └── novel_search_tool.py # 小说搜索工具
└── docs/
└── novel-recommender-tutorial.md # 本教程
2.3 步骤一: 加载必要技能
在开发前,我们需要加载 Coze 提供的技能包:
加载联网搜索技能
python
# 这个技能用于获取实时小说信息
from coze_coding_dev_sdk import SearchClient
from coze_coding_utils.runtime_ctx.context import new_context
# 初始化搜索客户端
ctx = new_context(method="search.novel")
client = SearchClient(ctx=ctx)
# 执行搜索
response = client.web_search(
query="玄幻小说推荐",
count=5,
need_summary=True
)
# 处理结果
for item in response.web_items:
print(f"标题: {item.title}")
print(f"简介: {item.snippet}")
print(f"链接: {item.url}")
加载大模型技能
python
# 用于语言理解和推理
from coze_coding_dev_sdk import LLMClient
from langchain_core.messages import HumanMessage, SystemMessage
ctx = new_context(method="invoke")
client = LLMClient(ctx=ctx)
# 调用模型
messages = [
SystemMessage(content="你是小说推荐专家"),
HumanMessage(content="推荐几本玄幻小说")
]
response = client.invoke(messages=messages)
print(response.content)
2.4 步骤二: 开发小说搜索工具
创建 src/tools/novel_search_tool.py:
python
from langchain.tools import tool, ToolRuntime
from coze_coding_dev_sdk import SearchClient
from coze_coding_utils.runtime_ctx.context import new_context
@tool
def search_novel_info(query: str, runtime: ToolRuntime = None) -> str:
"""
搜索小说相关信息,包括书名、作者、简介、评分等。
参数:
query: 搜索关键词(小说名称、作者名等)
"""
try:
# 1. 获取上下文 (重要: 必须使用 runtime.context)
ctx = runtime.context if runtime else new_context(method="search.novel")
# 2. 初始化搜索客户端
client = SearchClient(ctx=ctx)
# 3. 执行搜索
response = client.web_search(
query=f"{query} 小说",
count=5,
need_summary=True
)
# 4. 格式化结果
if not response.web_items:
return f"未找到关于 '{query}' 的小说信息。"
result = f"📚 关于 '{query}' 的小说搜索结果:\n\n"
for i, item in enumerate(response.web_items, 1):
result += f"【{i}】{item.title}\n"
result += f" 简介: {item.snippet[:150]}...\n"
result += f" 链接: {item.url}\n\n"
return result
except Exception as e:
return f"搜索出错: {str(e)}"
💡 关键要点:
- 必须使用
@tool装饰器 ctx参数必须使用runtime.context,不能自己构造- 工具必须返回
str类型 - 做好错误处理,避免工具崩溃影响 Agent
2.5 步骤三: 配置模型和提示词
创建 config/agent_llm_config.json:
json
{
"config": {
"model": "doubao-seed-1-8-251228",
"temperature": 0.8,
"top_p": 0.9,
"max_completion_tokens": 4096,
"timeout": 600,
"thinking": "disabled"
},
"sp": "你是小说推荐专家...",
"tools": ["search_novel_info", "search_novel_by_genre"]
}
字段说明:
model: 模型 ID,必须从技能服务获取或用户指定temperature: 创造性程度 (0-2,越高越随机)sp: 系统提示词,定义 Agent 的角色和行为tools: 可用工具列表
提示词编写技巧:
markdown
# 角色定义
清晰定义 Agent 的身份、专业领域、语气
# 任务目标
明确 Agent 需要完成的核心任务
# 能力
列出 Agent 拥有的能力(包括工具)
# 过程
详细描述工作流程,指导 Agent 如何行动
# 输出格式
定义输出的结构,便于用户阅读和后续处理
# 约束
设定行为边界,避免不当行为
2.6 步骤四: 编写 Agent 核心代码
创建 src/agents/agent.py:
python
import os
import json
from typing import Annotated
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langgraph.graph import MessagesState
from langgraph.graph.message import add_messages
from langchain_core.messages import AnyMessage
from coze_coding_utils.runtime_ctx.context import default_headers
# 导入工具
from tools.novel_search_tool import search_novel_info, search_novel_by_genre
# 导入记忆存储
from storage.memory.memory_saver import get_memory_saver
# 配置
LLM_CONFIG = "config/agent_llm_config.json"
MAX_MESSAGES = 40 # 保留最近 20 轮对话
# 滑动窗口消息管理
def _windowed_messages(old, new):
"""只保留最近 MAX_MESSAGES 条消息"""
return add_messages(old, new)[-MAX_MESSAGES:]
class AgentState(MessagesState):
messages: Annotated[list[AnyMessage], _windowed_messages]
def build_agent(ctx=None):
"""构建小说推荐智能体"""
# 1. 读取配置
workspace_path = os.getenv("COZE_WORKSPACE_PATH")
config_path = os.path.join(workspace_path, LLM_CONFIG)
with open(config_path, 'r', encoding='utf-8') as f:
cfg = json.load(f)
# 2. 初始化 LLM
api_key = os.getenv("COZE_WORKLOAD_IDENTITY_API_KEY")
base_url = os.getenv("COZE_INTEGRATION_MODEL_BASE_URL")
llm = ChatOpenAI(
model=cfg['config']['model'],
api_key=api_key,
base_url=base_url,
temperature=cfg['config']['temperature'],
streaming=True,
default_headers=default_headers(ctx) if ctx else {}
)
# 3. 准备工具
tools = [search_novel_info, search_novel_by_genre]
# 4. 创建 Agent
return create_agent(
model=llm,
system_prompt=cfg['sp'],
tools=tools,
checkpointer=get_memory_saver(), # 短期记忆
state_schema=AgentState
)
💡 关键要点:
- 使用
create_agent创建 Agent checkpointer提供记忆能力state_schema定义状态结构- 工具必须在
tools列表中注册
2.7 测试智能体
使用 test_run 工具测试:
测试用例 1: 按类型推荐
输入: "我想看玄幻小说,能推荐几本吗?"
预期: 调用 search_novel_by_genre 工具,返回玄幻小说列表
测试用例 2: 查询特定小说
输入: "《完美世界》这本小说怎么样?"
预期: 调用 search_novel_info 工具,返回小说详情
测试用例 3: 多轮对话
输入: "我喜欢《完美世界》,还有类似的推荐吗?"
预期: 基于对话记忆,推荐类似风格的小说
高级篇 - 工作流编排与优化
3.1 工作流设计模式
小说推荐智能体可采用工具增强型对话流:
用户输入
↓
[LLM 理解意图]
↓
需要搜索? ─Yes─→ [调用搜索工具] ─→ [获取结果]
↓ No ↓
└─────────────→ [LLM 生成回复] ←─────────┘
↓
返回用户
3.2 记忆机制详解
短期记忆 (对话历史)
python
# 使用滑动窗口保留最近 40 条消息
MAX_MESSAGES = 40
def _windowed_messages(old, new):
return add_messages(old, new)[-MAX_MESSAGES:]
class AgentState(MessagesState):
messages: Annotated[list[AnyMessage], _windowed_messages]
优点 : 防止上下文过长,控制成本
缺点: 无法跨会话记忆
长期记忆 (可选扩展)
如需长期记忆,可集成数据库:
python
# 使用 Supabase 技能存储用户偏好
from skills.public.prod.supabase import SupabaseClient
async def save_user_preference(user_id: str, preference: dict):
client = SupabaseClient()
await client.table('user_preferences').insert({
'user_id': user_id,
'favorite_genres': preference['genres'],
'favorite_authors': preference['authors']
})
3.3 性能优化
1. 模型选择策略
| 任务类型 | 推荐模型 | 原因 |
|---|---|---|
| 简单对话 | doubao-seed-1-6-lite | 快速、低成本 |
| 复杂推理 | doubao-seed-2-0-pro | 强推理能力 |
| 多模态 | doubao-seed-1-6-vision | 支持图片/视频 |
2. 提示词优化
markdown
# 优化前 (太简单)
你是小说推荐助手,帮用户推荐小说。
# 优化后 (结构化、明确)
# 角色定义
你是小说推荐专家,精通各类文学作品...
# 任务目标
1. 理解用户偏好
2. 搜索小说信息
3. 生成个性化推荐
# 约束
- 必须使用工具搜索真实信息
- 不编造小说内容
- 推荐理由要具体
3. 工具调用优化
- 缓存: 对相同搜索查询进行缓存
- 并行: 多个工具可并行调用
- 超时控制: 设置合理的 timeout
python
# 在工具中添加缓存
from functools import lru_cache
@lru_cache(maxsize=100)
def cached_search(query: str):
# 缓存搜索结果
...
最佳实践
4.1 开发规范
✅ 必须遵守:
- 工具定义放在
src/tools/目录 - Agent 代码放在
src/agents/agent.py - 配置文件放在
config/目录 - 使用相对路径导入 (
from tools.xxx import xxx) - 工具必须使用
@tool装饰器 - ctx 参数使用
runtime.context
❌ 禁止行为:
- 禁止在 import 路径中包含
src.前缀 - 禁止工具内部调用其他
@tool函数 - 禁止编造模型 ID
- 禁止使用 Mock 数据
- 禁止在客户端代码中暴露 API Key
4.2 调试技巧
1. 查看日志
bash
# 查看最新 20 行日志
tail -n 20 /app/work/logs/bypass/app.log
# 搜索错误
grep -n "Error\|Exception" /app/work/logs/bypass/app.log | tail -n 20
2. 分步测试
python
# 1. 测试工具独立运行
result = search_novel_info("完美世界")
print(result)
# 2. 测试 Agent 构建
agent = build_agent()
print(agent)
# 3. 测试完整流程
# 使用 test_run 工具
3. 错误处理
python
from langchain.agents.middleware import wrap_tool_call
from langchain.messages import ToolMessage
@wrap_tool_call
def handle_tool_errors(request, handler):
"""工具错误处理中间件"""
try:
return handler(request)
except Exception as e:
return ToolMessage(
content=f"工具执行错误: {str(e)}",
tool_call_id=request.tool_call["id"]
)
# 在 build_agent 中使用
agent = create_agent(
model=llm,
tools=tools,
middleware=[handle_tool_errors] # 添加错误处理
)
4.3 安全注意事项
-
API Key 保护:
python# ❌ 错误: 硬编码 API Key api_key = "sk-xxxxx" # ✅ 正确: 从环境变量读取 api_key = os.getenv("COZE_WORKLOAD_IDENTITY_API_KEY") -
输入验证:
python@tool def search_novel_info(query: str, runtime: ToolRuntime = None) -> str: # 验证输入 if not query or len(query) > 100: return "搜索关键词不能为空或超过100字符" # 执行搜索 ... -
敏感信息过滤:
python# 在工具返回前过滤敏感信息 def sanitize_result(text: str) -> str: # 过滤电话号码、邮箱等 import re text = re.sub(r'\d{11}', '***', text) # 手机号 text = re.sub(r'[\w\.-]+@[\w\.-]+', '***', text) # 邮箱 return text
常见问题 FAQ
Q1: 如何选择合适的模型?
A: 根据任务复杂度和成本考虑:
- 简单对话 :
doubao-seed-1-6-lite(快速、低成本) - 复杂任务 :
doubao-seed-2-0-pro(强推理能力) - 多模态 :
doubao-seed-1-6-vision(支持图片/视频) - 默认选择 :
doubao-seed-1-8-251228(平衡性能与成本)
Q2: 工具调用失败怎么办?
A: 检查以下几点:
- 工具是否正确注册到 Agent 的 tools 列表
- ctx 参数是否使用
runtime.context - 查看日志
/app/work/logs/bypass/app.log - 添加错误处理中间件
Q3: 如何让 Agent 记住用户偏好?
A: 两种方式:
- 短期记忆 : 使用
checkpointer(已实现) - 长期记忆: 集成数据库 (Supabase/PostgreSQL)
Q4: Agent 响应太慢怎么办?
A: 优化策略:
- 使用更轻量的模型
- 减少 max_completion_tokens
- 对工具调用进行缓存
- 使用流式输出 (streaming=True)
Q5: 如何扩展更多功能?
A: 三个步骤:
- 开发新工具 : 在
src/tools/下创建新工具 - 更新配置 : 在
config/agent_llm_config.json的 tools 列表中添加 - 更新提示词: 在 sp 中描述新工具的使用方式
Q6: 能否使用自己的模型?
A : 可以,通过 volcano-ark 技能:
python
# 加载火山方舟技能
load_skill("/skills/public/prod/volcano-ark")
# 使用自己的 API Key
llm = ChatOpenAI(
model="your-model-id",
api_key="your-api-key",
base_url="your-base-url"
)
总结
通过本教程,你学会了:
✅ 入门知识:
- 智能体的核心概念和组件
- Coze 本地部署的优势
✅ 实战技能:
- 加载和使用技能包
- 开发和调试工具
- 配置模型和提示词
- 构建 Agent 核心代码
✅ 高级技巧:
- 工作流设计模式
- 记忆机制实现
- 性能优化策略
✅ 最佳实践:
- 开发规范
- 调试技巧
- 安全注意事项
下一步建议:
- 尝试添加更多工具 (如评分查询、书评搜索)
- 集成数据库实现长期记忆
- 开发 Web 界面与用户交互
- 优化提示词提升推荐质量
附录: 完整代码示例
所有代码已在本教程对应章节提供,项目结构如下:
/workspace/projects/
├── config/
│ └── agent_llm_config.json
├── src/
│ ├── agents/
│ │ └── agent.py
│ └── tools/
│ └── novel_search_tool.py
└── docs/
└── novel-recommender-tutorial.md
运行方式:
- 确保环境变量已配置
- 使用
test_run工具测试 - 或通过
python src/main.py启动服务
📝 教程版本 : v1.0
最后更新 : 2025-01-XX
作者: Coze Coding Team