ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于FastAPI与Claude Code构建智能音箱AI Agent编程助手

2026/8/13 12:03:26 拓冰建站 浏览量
基于FastAPI与Claude Code构建智能音箱AI Agent编程助手 1. 项目概述当智能音箱遇上AI Agent最近在折腾一个挺有意思的玩意儿把我家那个只会报天气、放音乐的小度音箱接入了最近技术圈里讨论度很高的“小龙虾”。这里的“小龙虾”可不是餐桌上的美食而是指一个名为Claude Code的AI编程助手因为其图标酷似一只龙虾钳子加上其强大的“智能体”Agent能力被开发者们戏称为“小龙虾”。这个项目的核心就是让小度音箱这个物理终端能够调用“小龙虾”这个云端大脑的推理和代码执行能力实现从“语音助手”到“AI智能体”的跨越。听起来有点玄乎简单说以前你问小度“帮我写个Python函数计算斐波那契数列。”它大概率会回答“我还在学习中”或者直接播放一首相关的歌曲。但现在经过改造后小度可以理解你的指令将其转化为一个明确的“任务”然后调用后端的“小龙虾”Agent让这个Agent去思考、编写代码、甚至执行测试最后把生成的结果或代码片段再用语音播报给你听。整个过程小度扮演了“耳朵”、“嘴巴”和任务调度者的角色而“小龙虾”则是真正的“大脑”和“双手”。这不仅仅是简单的API调用拼接它涉及到几个关键层的打通语音识别与指令解析、任务意图的抽象与封装、与AI Agent框架的安全、稳定交互以及结果的反向语音合成。对于开发者、极客或者只是想给智能家居增添点“黑科技”趣味的朋友来说这个项目融合了硬件交互、软件集成和前沿AI应用是一个绝佳的练手机会。它能让你深入理解现代AI Agent的工作流并亲手打造一个属于你自己的、能听会思考、还能动手写代码的“超级语音助手”。2. 核心思路与技术选型解析要实现“小度指挥小龙虾”我们不能蛮干需要一个清晰、可扩展的架构。整个系统的核心思路是构建一个中间件服务作为小度音箱技能和Claude Code AI Agent之间的桥梁。这个服务需要完成指令的接收、转换、派发和回传。2.1 整体架构设计我设计的架构分为三层前端交互层小度音箱DuerOS。它负责采集用户语音通过百度官方技能平台将语音识别ASR后的文本指令以HTTP请求的形式发送到我们自定义的技能服务后端。中间逻辑层自定义后端服务中间件。这是本项目的核心我用Python的FastAPI框架快速搭建。它接收小度的请求解析用户意图。如果意图是“编程”或“代码”相关例如包含“写代码”、“调试”、“解释”等关键词则将该指令进一步封装成符合Claude Code API格式的请求并发起调用。之后它需要处理Claude Code返回的可能是多轮的响应将其整合成一段自然、简洁的文本最后按照小度技能平台的响应格式要求进行封装返回给小度。后端AI能力层Claude Code小龙虾API。这是提供核心AI能力的云服务。我们的中间件通过其提供的API将编程任务描述发送过去Claude Code会在一个安全的沙箱环境中进行思考、代码编写和逻辑推理并将结果返回。这个架构的优势在于解耦。小度技能平台只与我们的中间件对话完全感知不到后端是Claude还是其他AI模型。同样我们的中间件也可以灵活替换后端的AI服务提供商只需适配不同的API接口即可扩展性很强。2.2 关键技术组件选型小度技能平台选择它是因为小度音箱硬件普及率高其技能开发平台文档完善提供了标准的技能创建、测试和发布流程。我们需要创建一个“自定义技能”配置好服务端点即我们的中间件服务器地址。后端框架选用Python FastAPI。Python在AI和脚本领域生态丰富FastAPI轻量、异步支持好、自动生成API文档非常适合快速构建这种代理服务。相比Django或Flask它在处理高频、低延迟的API转发场景下更高效。AI Agent服务核心是Claude Code API。选择它而非直接使用ChatGPT等通用模型的原因在于Claude Code专为编程场景优化内置了代码执行沙箱。这意味着它不仅能生成代码还能“运行”代码看到结果进行自我调试和修正这对于完成一个完整的编程任务至关重要。这正是一个“Agent”智能体的典型行为感知理解任务、规划思考步骤、执行写代码、运行、反馈输出结果或修正错误。部署与通信服务器可以选择一台有公网IP的云服务器如腾讯云、阿里云ECS或者利用内网穿透工具如ngrok、frp将本地开发机临时暴露到公网供小度平台回调。重要提示小度技能服务端要求回调地址必须是HTTPS这意味着你需要为你的服务配置SSL证书可以使用Let‘s Encrypt免费证书。通信协议全程使用HTTP/HTTPS协议。小度平台到中间件中间件到Claude API都是标准的RESTful API调用。注意在调用任何第三方AI API特别是像Claude Code这类能执行代码的服务时必须在中间件层做好指令过滤和权限控制。绝对不能让用户通过小度音箱发送诸如“删除服务器所有文件”或访问敏感信息的指令。需要在中间件逻辑里加入关键词黑名单和意图白名单机制这是一个严肃的安全考量。3. 详细实现步骤与核心代码拆解下面我将分步拆解如何将这个想法落地。请确保你已具备一个小度音箱、一个百度开发者账号、一个可用的Claude API Key或同等能力的AI编程助手API、以及一台用于部署中间件的服务器或具备内网穿透条件的本地电脑。3.1 第一步搭建中间件服务骨架首先我们创建项目并安装依赖。# 创建项目目录 mkdir dueros_claude_agent cd dueros_claude_agent # 创建虚拟环境推荐 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 安装核心依赖 pip install fastapi uvicorn httpx python-dotenv创建主程序文件main.pyfrom fastapi import FastAPI, Request, HTTPException from pydantic import BaseModel import httpx import os from dotenv import load_dotenv import json import re # 加载环境变量 load_dotenv() app FastAPI(titleDuerOS-Claude Agent Bridge) # 从环境变量读取配置 CLAUDE_API_KEY os.getenv(CLAUDE_API_KEY) CLAUDE_API_URL https://api.anthropic.com/v1/messages # 以Claude API为例实际需替换为Claude Code的API端点 DUEROS_VERIFICATION_TOKEN os.getenv(DUEROS_VERIFICATION_TOKEN) # 小度技能平台配置的校验token # 定义小度请求和响应的数据结构根据DuerOS文档 class DuerOSRequest(BaseModel): version: str session: dict context: dict request: dict class DuerOSResponse(BaseModel): version: str sessionAttributes: dict {} response: dict async def call_claude_agent(prompt: str) - str: 调用Claude Code API处理编程任务 headers { x-api-key: CLAUDE_API_KEY, anthropic-version: 2023-06-01, content-type: application/json } # 构建符合Claude API格式的请求体 # 注意Claude Code可能有特定的模型名称和参数此处为示例 data { model: claude-3-5-sonnet-20241022, # 示例模型请替换为Claude Code的正确模型名 max_tokens: 1024, messages: [{role: user, content: prompt}], system: 你是一个专业的编程助手Claude Code。请根据用户请求编写、解释或调试代码。确保代码正确且安全。 } async with httpx.AsyncClient(timeout30.0) as client: try: resp await client.post(CLAUDE_API_URL, headersheaders, jsondata) resp.raise_for_status() result resp.json() # 解析Claude的回复内容这里需要根据实际API响应结构调整 # 通常内容在 result[content][0][text] 中 claude_reply result.get(content, [{}])[0].get(text, 抱歉我没有得到有效的回复。) return claude_reply except httpx.RequestError as e: return f调用AI服务时出现网络错误{e} except (KeyError, json.JSONDecodeError) as e: return f解析AI服务响应时出错{e} def is_programming_task(query: str) - bool: 简单判断用户指令是否为编程相关任务 programming_keywords [代码, 编程, 写一个, 函数, 调试, python, java, 解释一下, 算法, 如何实现] query_lower query.lower() return any(keyword in query_lower for keyword in programming_keywords) def sanitize_response(text: str) - str: 对AI返回的文本进行清洗使其更适合语音播报 # 移除过长的代码块用简短说明代替 text re.sub(r[\s\S]*?, [此处有代码片段请在手机端查看详情], text) # 缩短过长的输出 if len(text) 300: text text[:300] ...内容过长已截断 return text app.post(/dueros) async def handle_dueros_request(dueros_req: DuerOSRequest, request: Request): 处理小度技能平台发来的所有请求 # 1. 验证请求可选但推荐 # 实际生产中应验证请求签名此处简化 token request.headers.get(Authorization) # 可在此处添加token验证逻辑 # 2. 解析用户指令 req_type dueros_req.request.get(type) if req_type ! IntentRequest: # 处理LaunchRequest或SessionEndedRequest等 return build_simple_response(欢迎使用编程助手技能你可以让我帮你写代码或解释编程问题。) user_query dueros_req.request.get(intent, {}).get(slots, {}).get(query, {}).get(value, ) if not user_query: return build_simple_response(我没听清楚请再说一遍。) # 3. 判断意图并分流 if is_programming_task(user_query): # 交给Claude Agent处理 ai_response await call_claude_agent(f用户通过语音助手提问请用简洁清晰的语言回答适合语音播报。问题{user_query}) speech_text sanitize_response(ai_response) else: # 非编程问题可以用其他方式回答或直接回复 speech_text f“您的问题‘{user_query}’不是编程类问题。目前我主要擅长处理代码编写、调试和解释等任务。” # 4. 构建返回给小度的响应 return build_response(speech_text) def build_simple_response(speech_text): 构建一个简单的技能响应 return { version: 2.0, sessionAttributes: {}, response: { outputSpeech: { type: PlainText, text: speech_text }, shouldEndSession: True } } def build_response(speech_text, session_attrsNone): 构建完整的技能响应 if session_attrs is None: session_attrs {} return DuerOSResponse( version2.0, sessionAttributessession_attrs, response{ outputSpeech: { type: PlainText, text: speech_text }, card: { type: Simple, title: 编程助手, content: speech_text[:200] # 卡片显示内容 }, shouldEndSession: True # 单轮对话结束后关闭会话 } ).dict() if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)同时创建一个.env文件来保存敏感信息切勿提交到代码仓库CLAUDE_API_KEYyour_claude_api_key_here DUEROS_VERIFICATION_TOKENyour_dueros_token_here3.2 第二步配置小度技能平台登录百度DuerOS开放平台进入“技能开发”部分创建“自定义技能”。配置技能信息填写技能名称如“AI编程助手”、调用名称如“打开编程助手”、图标等。配置意图这是关键。你需要定义一个意图Intent例如“ProgrammingIntent”。为其添加一个用户话术槽位Slot比如命名为query用于接收用户说的完整句子。在“用户说法”里添加一些示例如“帮我写一个Python排序函数”、“解释一下什么是递归”、“用Java实现一个单例模式”。配置服务端点在“配置”部分填写你的中间件服务的公网HTTPS地址例如https://your-server.com/dueros。路径/dueros需要和上面代码中的app.post(/dueros)保持一致。提交测试保存配置后可以在平台的测试页面进行模拟测试输入文本看是否能收到你中间件返回的响应。实操心得小度技能平台的意图配置需要一定量的示例话术来提升识别准确率。建议至少为每个意图准备20-30条不同表达方式的例句。另外平台对HTTPS证书有要求自签名证书通常不行必须使用受信任的CA颁发的证书如Let‘s Encrypt。这是调试初期最容易卡住的地方。3.3 第三步部署中间件并建立连接服务器部署将你的main.py和.env文件上传到云服务器。安装Python环境及依赖。配置HTTPS使用Nginx反向代理你的FastAPI应用并配置SSL证书。一个简单的Nginx配置示例如下server { listen 443 ssl; server_name your-server.com; ssl_certificate /path/to/your/fullchain.pem; ssl_certificate_key /path/to/your/privkey.pem; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }然后使用sudo systemctl restart nginx重启Nginx。启动服务在服务器上进入项目目录激活虚拟环境使用uvicorn main:app --host 0.0.0.0 --port 8000启动服务。为了持久化建议使用systemd或supervisor来管理进程。连接测试确保你的服务器8000端口可访问且Nginx代理配置正确。可以先用curl或 Postman 向https://your-server.com/dueros发送一个模拟的小度请求JSON测试中间件是否能正常响应。小度端联调在小度技能平台提交测试并最终在真实的小度音箱上通过“小度小度打开编程助手”来唤醒技能并进行语音对话测试。4. 核心功能深化与优化策略基础功能跑通后你会发现一些待优化点。一个真正好用的Agent需要更智能的交互和更稳定的服务。4.1 实现多轮对话与上下文保持上面的示例是单轮对话shouldEndSession: True。但编程任务常常需要多轮澄清比如用户说“写个函数”你可能需要问“用什么语言”。我们需要修改逻辑来保持会话状态。修改思路利用Session小度平台会在请求中携带session信息。我们可以将和Claude对话的上下文如Conversation ID或历史消息存储在中间件的缓存如Redis中Key使用小度的sessionId。修改响应将shouldEndSession设为False并在sessionAttributes中存储我们的上下文标识。修改Claude调用每次调用Claude时不仅发送当前问题还附加上一轮的历史消息让AI能理解对话脉络。# 伪代码示例需结合具体缓存方案实现 from typing import Optional import redis.asyncio as redis # 初始化Redis连接 redis_client redis.from_url(redis://localhost:6379) async def handle_dueros_request(dueros_req: DuerOSRequest): session_id dueros_req.session.get(sessionId) user_query get_query(dueros_req) # 从Redis获取该会话的历史消息列表 history_key fclaude_history:{session_id} history_messages await redis_client.lrange(history_key, 0, -1) # 获取列表 history_messages [json.loads(msg) for msg in history_messages] # 将用户新问题加入历史 history_messages.append({role: user, content: user_query}) # 调用Claude传入整个历史 claude_response await call_claude_with_history(history_messages) # 将Claude的回复也加入历史 history_messages.append({role: assistant, content: claude_response}) # 只保留最近N轮对话防止过长 if len(history_messages) 10: history_messages history_messages[-10:] # 将更新后的历史存回Redis并设置过期时间如30分钟 pipe redis_client.pipeline() pipe.delete(history_key) for msg in history_messages: pipe.rpush(history_key, json.dumps(msg)) pipe.expire(history_key, 1800) await pipe.execute() # 构建响应保持会话 return build_response(claude_response, session_attrs{has_context: true}, should_end_sessionFalse)4.2 增强指令安全过滤与意图识别之前的is_programming_task函数过于简单。我们需要更鲁棒的方案。使用更精准的意图分类可以引入一个轻量级的本地文本分类模型如用scikit-learn训练的模型或者调用一个专门的意图识别API如百度UNIT来更准确地区分“编程问题”、“闲聊”、“设备控制”等。构建指令黑名单与安全沙箱黑名单在中间件层对user_query进行扫描过滤掉明显危险的命令如包含“rm -rf”、“format”、“drop database”、“sudo”等关键词的指令。沙箱限制虽然Claude Code有自己的沙箱但我们可以在发起请求前对任务描述进行“无害化”提示。例如在发给Claude的system prompt中强调“你是一个在安全沙箱中运行的助手无法执行任何访问外部网络、文件系统或进行高危操作的命令。请仅生成安全的、演示性的代码。”4.3 优化语音播报体验AI生成的代码或解释文本直接TTS语音合成出来体验可能很差。需要做针对性优化文本预处理代码块替换如上文sanitize_response函数所示将长代码块替换为提示语。符号读法转换将“-”转换为“箭头”“”转换为“双等号”“\n”转换为“换行”等。长句切分对于生成的冗长解释可以按句号、分号切分成更短的句子让小度逐句播报听起来更自然。支持多种结果格式除了语音播报可以利用小度技能支持的“卡片”Card功能在配套的手机App如小度App上显示更丰富的内容如高亮显示的代码、运行结果的截图需Claude API返回相关数据等。语音播报摘要详情请查看手机这是一种很好的互补体验。5. 常见问题排查与实战调试记录在实际搭建和调试过程中我遇到了不少坑。这里把典型问题和解决方案记录下来希望能帮你节省时间。5.1 网络与部署相关问题问题现象可能原因排查步骤与解决方案小度平台测试时提示“服务端返回错误”或超时。1. 中间件服务未启动或端口不对。2. 服务器防火墙/安全组未开放端口。3. Nginx配置错误代理未生效。4. 中间件代码有未处理的异常导致崩溃。1. 在服务器上curl http://localhost:8000/dueros测试本地服务是否正常。2. 用telnet your-server.com 443检查公网端口是否可达。3. 检查Nginx错误日志sudo tail -f /var/log/nginx/error.log。4. 在中间件代码中添加更详细的日志捕获异常并返回友好错误信息给小度平台。HTTPS证书不受信任。使用了自签名证书或证书链不完整。申请免费的Let‘s Encrypt证书使用certbot工具。确保Nginx配置中指向了正确的证书和密钥文件路径。内网穿透工具如ngrok生成的域名小度平台无法访问。某些内网穿透服务使用的域名或IP可能被小度平台的安全策略屏蔽。最稳定的方案是使用正规云服务器备案域名如需。如果仅为测试可尝试更换不同的内网穿透服务商或检查其域名是否在常见黑名单中。5.2 小度技能平台配置问题问题现象可能原因排查步骤与解决方案唤醒技能后小度没反应或说“技能出错了”。1. 意图Intent配置不正确用户说法未匹配。2. 服务端点URL填写错误。3. 中间件返回的响应格式不符合小度协议。1. 在技能平台的“模拟测试”中输入你期望的指令文本看是否能匹配到你定义的意图。多补充一些用户说法。2. 仔细核对端点URL确保是HTTPS且路径正确。3. 使用平台提供的“在线测试”功能查看原始请求和响应。严格按照DuerOS技能协议文档构建返回的JSON结构。一个常见的错误是字段名或层级不对。技能可以唤醒但识别到的文本不对。小度语音识别ASR误差。在技能配置中可以尝试添加“语音交互”配置选择更贴近你使用场景的领域模型如“教育学习”。在用户说法中加入更多同义、口语化的表达提高容错率。5.3 Claude API调用与逻辑问题问题现象可能原因排查步骤与解决方案中间件日志显示调用Claude API失败返回4xx/5xx错误。1. API Key错误或过期。2. 请求格式不符合Claude API要求。3. 请求频率超限或额度不足。1. 检查.env文件中的CLAUDE_API_KEY是否正确是否有空格。2. 查阅最新的Claude API官方文档核对请求头Headers和请求体Body的格式。特别注意anthropic-version等必需头。3. 登录Claude API控制台查看用量和额度。Claude返回了内容但播报出来是乱码或截断的。1. 返回内容包含特殊字符或编码问题。2. 文本过长超过小度单次播报限制。3.sanitize_response函数处理不当。1. 在中间件中对Claude返回的文本进行编码检查和清洗如response.text.encode(‘utf-8’).decode(‘utf-8’)。2. 小度单次播报文本有长度限制通常几百字必须进行截断或分页。我们的sanitize_response函数已经做了初步处理可能需要根据实际体验调整阈值。3. 检查正则表达式替换代码块是否正常工作避免误删正常内容。多轮对话时上下文混乱或丢失。1. Session管理逻辑有bug。2. Redis缓存未正确设置或过期时间太短。3. 历史消息拼接方式错误导致Claude理解混乱。1. 打印或记录每次请求的sessionId和从Redis获取的历史消息确认存储和读取是否正确。2. 检查Redis服务是否运行连接是否正常。给Session Key设置合理的过期时间如30分钟。3. 确保发送给Claude的历史消息列表格式正确是[{role: user, content: ...}, {role: assistant, content: ...}, ...]这样的数组。5.4 安全与体验优化问题问题现象可能原因排查步骤与解决方案用户通过语音发送了危险指令测试时。安全过滤规则太弱或未生效。强化is_programming_task函数和黑名单机制。考虑引入更严格的“任务模板”例如只允许几种固定模式“用[语言]写一个[功能]代码”、“解释[概念]”、“调试以下代码[代码片段]”。对于不符合模板的指令直接回复“暂不支持该类型问题”。语音播报代码时体验很差听不清。代码结构不适合语音朗读。坚持“摘要播报详情看卡片”的原则。在发给Claude的指令中明确要求“请先给出非常简短一两句话的口语化总结适合语音播报。然后在后续内容中提供详细代码和解释。” 然后在中间件中只提取第一段总结用于TTS完整内容放在响应卡的content字段。整个项目调试的过程其实就是不断在“用户说人话”、“小度转文本”、“中间件理解意图”、“AI处理任务”、“结果转成人话”这个链条上查找薄弱环节。耐心地使用日志记录每个环节的输入输出是快速定位问题的关键。当你第一次听到小度用语音清晰地播报出它“思考”后生成的代码逻辑时那种感觉确实非常奇妙仿佛真的给冷冰冰的智能音箱注入了一个会编程的灵魂。这个项目最大的收获不是最终的产品而是在集成过程中对AI Agent工作流、服务安全边界和用户体验细节的深刻理解。