CoPaw Agent Python 客户端开发指南:实现流式响应与实时打印
前言
在 AI Agent 应用开发中,如何与本地部署的 AI 服务进行高效通信是一个常见需求。本文将介绍如何使用 Python 实现一个 CoPaw Agent 客户端,支持流式响应(Streaming)和实时打印功能,让你能够像使用 ChatGPT 一样获得流畅的对话体验。
什么是 CoPaw?
CoPaw 是一个本地部署的多智能体协作系统。
通过本文的 Python 客户端,你可以:
- ✅ 检查服务状态
- ✅ 创建和管理会话
- ✅ 发送消息并获取流式响应
- ✅ 实时打印 AI 回复内容
- ✅ 停止正在进行的对话
核心功能设计
1. 客户端初始化
python
class CoPawClient:
def __init__(self, host: str = "127.0.0.1", port: int = 8088):
self.base_url = f"http://{host}:{port}/api"
self.session = requests.Session()
self.session.headers["x-agent-id"] = TO_AGENT
self.host = host
self.port = port
关键点:
- 使用
requests.Session()保持连接,提高性能 - 设置
x-agent-id请求头,标识目标 Agent - 默认连接本地 8088 端口
2. 服务健康检查
python
def check_server(self) -> bool:
try:
response = self.session.get(f"{self.base_url}/chats", timeout=5)
return response.status_code == 200
except requests.exceptions.RequestException:
return False
在发送请求前先检查服务是否可用,避免无谓的等待。
3. 流式响应的核心实现
这是本客户端的核心亮点------真正的流式迭代器:
python
def _stream_sse(self, response) -> Iterator[Dict[str, Any]]:
"""
【真正的流式迭代器】
每收到一段数据就立即返回,实现实时输出
"""
for line in response.iter_lines(decode_unicode=True):
if not line:
continue
line = line.strip()
if line.startswith("data: "):
data_str = line[6:]
if data_str.strip() == "[DONE]":
break
try:
data = json.loads(data_str)
if data.get("type") == "message" and data.get("content"):
yield data # 实时返回每一段数据
except json.JSONDecodeError:
continue
技术要点:
- 使用 SSE(Server-Sent Events)协议接收流式数据
iter_lines(decode_unicode=True)逐行读取响应yield关键字实现生成器,边接收边返回- 解析
data:前缀的 SSE 数据格式
4. 发送消息接口
python
def send_message(
self,
channel: str,
user_id: str,
session_id: str,
content: str,
stream: bool = True,
) -> Union[Iterator[Dict[str, Any]], Dict[str, Any]]:
response = self.session.post(
f"{self.base_url}/console/chat",
json={
"channel": channel,
"user_id": user_id,
"session_id": session_id,
"input": [
{"role": "user", "content": [{"type": "text", "text": content}]}
],
"stream": stream,
},
stream=stream,
timeout=1200, # 1200 秒超时=12 分钟
)
response.raise_for_status()
if stream:
return self._stream_sse(response) # 返回生成器
else:
return self._parse_sse_response(response.text)
设计亮点:
- 支持流式和非流式两种模式
- 长超时设置(12 分钟),适应复杂任务
- 统一接口,灵活切换
5. 实时打印示例
python
# 设置 UTF-8 编码,避免 emoji 等特殊字符编码错误
import sys
sys.stdout.reconfigure(encoding='utf-8')
# 流式示例(实时输出)
print("AI 回复:", end="", flush=True)
full_text = ""
# 迭代获取实时流数据
for chunk in client.send_message_by_session(
user_id=USER_ID,
channel=CHANNEL,
session_id=SESSION_ID,
content=content,
stream=True
):
# 提取文本
for content_item in chunk.get("content", []):
if content_item.get("type") == "text":
text = content_item.get("text", "")
full_text += text
print(text, end="", flush=True) # 实时打印!
print("\n\n【接收完成】")
关键技巧:
sys.stdout.reconfigure(encoding='utf-8')设置 UTF-8 输出,避免 emoji 编码错误end=""避免自动换行flush=True强制立即输出,不等待缓冲区- 累加
full_text便于后续处理
完整配置参数
python
# 对应请求头 x-agent-id: A6T8Kq
TO_AGENT = "fZd52L"
SESSION_ID = "1775560092236"
USER_ID = "default"
COPAW_IP = "127.0.0.1"
COPAW_PORT = 8088
CHANNEL = "console"
参数说明:
| 参数 | 说明 |
|---|---|
TO_AGENT |
目标 Agent ID,从 CoPaw 系统获取 |
SESSION_ID |
会话标识,保持对话连续性 |
USER_ID |
用户标识,默认为 "default" |
COPAW_IP/PORT |
CoPaw 服务地址 |
CHANNEL |
通信渠道,console 表示控制台 |
扩展功能
会话管理
python
def create_chat(self, session_id: str, user_id: str, channel: str = "console") -> Dict[str, Any]:
response = self.session.post(
f"{self.base_url}/chats",
json={"session_id": session_id, "user_id": user_id, "channel": channel},
)
response.raise_for_status()
return response.json()
def list_chats(self) -> list:
response = self.session.get(f"{self.base_url}/chats")
response.raise_for_status()
return response.json()
停止对话
python
def stop_chat(self, session_id: str) -> Dict[str, Any]:
list_chats = self.list_chats()
# 通过 session_id 查找 chat_id
chat_id = next((chat["chat_id"] for chat in list_chats if chat["session_id"] == session_id), None)
if chat_id is None:
raise ValueError(f"会话 ID {session_id} 不存在")
response = self.session.post(
f"{self.base_url}/console/chat/stop",
params={"chat_id": chat_id},
data=b""
)
response.raise_for_status()
return response.json()
使用场景
- CLI 工具开发:构建命令行 AI 助手
- 自动化脚本:集成 AI 能力到工作流
- 数据处理:批量处理文件并获取 AI 分析
- 原型验证:快速测试 Agent 功能
依赖安装
bash
pip install requests
常见问题
1. TypeError: unsupported operand type(s) for |
问题: Python 版本低于 3.10 时,| 联合类型语法不支持。
解决: 使用 Union 替代:
python
from typing import Union
# 错误(Python < 3.10)
) -> Iterator[Dict[str, Any]] | Dict[str, Any]:
# 正确(兼容所有版本)
) -> Union[Iterator[Dict[str, Any]], Dict[str, Any]]:
2. UnicodeEncodeError: 'gbk' codec can't encode character
问题: Windows 控制台默认 GBK 编码,无法处理 emoji 等 UTF-8 字符。
解决: 设置控制台输出为 UTF-8:
python
import sys
sys.stdout.reconfigure(encoding='utf-8')
总结
本文介绍的 CoPaw Python 客户端具有以下优势:
- 🚀 真正的流式响应:边接收边输出,用户体验流畅
- 🔧 灵活配置:支持多种参数定制
- 📦 完整功能:涵盖会话管理、消息发送、对话停止
- 🎯 易于集成:简洁的 API 设计,快速上手
- ✅ 兼容性好:支持 Python 3.8+,解决 Windows 编码问题
通过理解 SSE 流式通信和生成器的使用,你可以将这种模式应用到其他 AI 服务的客户端开发中。
附录:完整源码
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
CoPaw Agent Python 客户端(支持流式响应 + 实时打印)
功能特性:
- 支持 SSE 流式响应,实现类似 ChatGPT 的打字机效果
- 支持非流式模式,一次性获取完整回复
- 会话管理:创建、列出、停止会话
- 服务健康检查
- Windows 编码兼容:自动设置 UTF-8 输出
作者:
接口是根据浏览器请求链接获取的,有些不一定准确,也没找到Copaw的对接文档,自行测试吧
日期:2026-04-10
"""
import requests
from typing import Optional, Dict, Any, Iterator, Union
import json
# ==================== 配置参数 ====================
# 对应请求头 x-agent-id: A6T8Kq
# 目标 Agent ID,从 CoPaw 系统获取
TO_AGENT = "fZd52L"
# 会话标识,保持对话连续性
# 同一 session_id 的对话会有上下文记忆
SESSION_ID = "1775560092236"
# 用户标识,默认为 "default"
USER_ID = "default"
# CoPaw 服务地址
COPAW_IP = "127.0.0.1"
COPAW_PORT = 8088
# 通信渠道,console 表示控制台
CHANNEL = "console"
# ==================== CoPawClient 类 ====================
class CoPawClient:
"""
CoPaw Agent Python 客户端
提供与本地 CoPaw 服务通信的完整接口,
支持流式和非流式两种响应模式。
"""
def __init__(self, host: str = "127.0.0.1", port: int = 8088):
"""
初始化客户端
Args:
host: CoPaw 服务主机地址,默认本地
port: CoPaw 服务端口,默认 8088
"""
# 构建 API 基础 URL
self.base_url = f"http://{host}:{port}/api"
# 创建会话对象,保持连接提高性能
self.session = requests.Session()
# 设置请求头,标识目标 Agent
self.session.headers["x-agent-id"] = TO_AGENT
# 保存主机和端口信息
self.host = host
self.port = port
def check_server(self) -> bool:
"""
检查 CoPaw 服务是否可用
Returns:
bool: 服务可用返回 True,否则返回 False
"""
try:
# 尝试访问 chats 端点
response = self.session.get(f"{self.base_url}/chats", timeout=5)
return response.status_code == 200
except requests.exceptions.RequestException:
# 网络异常或超时
return False
def create_chat(
self, session_id: str, user_id: str, channel: str = "console"
) -> Dict[str, Any]:
"""
创建新会话
Args:
session_id: 会话标识
user_id: 用户标识
channel: 通信渠道,默认 console
Returns:
Dict: 创建结果,包含 chat_id 等信息
"""
response = self.session.post(
f"{self.base_url}/chats",
json={"session_id": session_id, "user_id": user_id, "channel": channel},
)
response.raise_for_status()
return response.json()
def list_chats(self) -> list:
"""
列出所有会话
Returns:
list: 会话列表
"""
response = self.session.get(f"{self.base_url}/chats")
response.raise_for_status()
return response.json()
def send_message(
self,
channel: str,
user_id: str,
session_id: str,
content: str,
stream: bool = True,
) -> Union[Iterator[Dict[str, Any]], Dict[str, Any]]:
"""
发送消息到 Agent
Args:
channel: 通信渠道
user_id: 用户标识
session_id: 会话标识
content: 消息内容
stream: 是否启用流式响应,默认 True
Returns:
流式模式下返回迭代器,非流式模式下返回完整响应字典
"""
# 发送 POST 请求到 console/chat 端点
response = self.session.post(
f"{self.base_url}/console/chat",
json={
"channel": channel,
"user_id": user_id,
"session_id": session_id,
"input": [
{"role": "user", "content": [{"type": "text", "text": content}]}
],
"stream": stream,
},
stream=stream, # 启用流式接收
timeout=1200, # 1200 秒超时 = 20 分钟,适应复杂任务
)
response.raise_for_status()
# 根据模式返回不同结果
if stream:
return self._stream_sse(response) # 返回生成器
else:
return self._parse_sse_response(response.text)
def _stream_sse(self, response) -> Iterator[Dict[str, Any]]:
"""
【核心功能】流式 SSE 响应迭代器
逐行读取服务器返回的 SSE 数据,每收到一段就立即 yield,
实现真正的实时输出效果。
Args:
response: requests 响应对象
Yields:
Dict: 解析后的数据块,包含 type 和 content 字段
"""
# 逐行迭代响应内容
for line in response.iter_lines(decode_unicode=True):
# 跳过空行
if not line:
continue
line = line.strip()
# SSE 数据以 "data: " 开头
if line.startswith("data: "):
data_str = line[6:] # 去掉 "data: " 前缀
# 遇到 [DONE] 表示传输结束
if data_str.strip() == "[DONE]":
break
try:
# 解析 JSON 数据
data = json.loads(data_str)
# 只返回 type 为 message 且有 content 的数据
if data.get("type") == "message" and data.get("content"):
yield data # 实时返回每一段数据
except json.JSONDecodeError:
# JSON 解析失败则跳过
continue
def _parse_sse_response(self, sse_text: str) -> Dict[str, Any]:
"""
解析 SSE 响应(非流式模式)
一次性解析完整的 SSE 响应文本,返回结构化结果。
Args:
sse_text: 完整的 SSE 响应文本
Returns:
Dict: 包含 messages、last_message 和 text 的字典
"""
messages = [] # 所有消息列表
last_message = None # 最后一条消息
text_parts = [] # 文本片段列表
# 逐行解析
for line in sse_text.strip().split("\n"):
if line.startswith("data: "):
data_str = line[6:]
if data_str.strip() == "[DONE]":
break
try:
data = json.loads(data_str)
if data.get("type") == "message":
messages.append(data)
last_message = data
# 提取文本内容
if data.get("content"):
for content_item in data.get("content", []):
if content_item.get("type") == "text":
text_parts.append(content_item.get("text", ""))
except json.JSONDecodeError:
continue
return {
"messages": messages,
"last_message": last_message,
"text": "".join(text_parts), # 拼接完整文本
}
def send_message_by_session(
self,
session_id: str,
content: str,
user_id: str = "default",
channel: str = "console",
stream: bool = True,
) -> Union[Iterator[Dict[str, Any]], Dict[str, Any]]:
"""
便捷的会话消息发送方法
简化参数,默认使用全局配置的 user_id 和 channel。
Args:
session_id: 会话标识
content: 消息内容
user_id: 用户标识,默认 "default"
channel: 通信渠道,默认 "console"
stream: 是否流式,默认 True
Returns:
同 send_message
"""
return self.send_message(
channel=channel,
user_id=user_id,
session_id=session_id,
content=content,
stream=stream,
)
def stop_chat(
self,
session_id: str
) -> Dict[str, Any]:
"""
停止正在进行的对话
通过 session_id 查找对应的 chat_id,然后发送停止请求。
Args:
session_id: 会话标识
Returns:
Dict: 停止操作结果
Raises:
ValueError: 会话不存在时抛出
"""
# 获取所有会话列表
list_chats = self.list_chats()
# 通过 session_id 查找 chat_id
chat_id = next(
(chat["chat_id"] for chat in list_chats if chat["session_id"] == session_id),
None
)
# 未找到会话则抛出异常
if chat_id is None:
raise ValueError(f"会话 ID {session_id} 不存在")
# 发送停止请求
response = self.session.post(
f"{self.base_url}/console/chat/stop",
params={"chat_id": chat_id},
data=b""
)
response.raise_for_status()
return response.json()
# ==================== 主程序入口 ====================
if __name__ == "__main__":
# 设置控制台输出为 UTF-8,避免 emoji 等特殊字符编码错误
# Windows 控制台默认 GBK 编码,需要显式设置为 UTF-8
import sys
sys.stdout.reconfigure(encoding='utf-8')
# 创建客户端实例
client = CoPawClient(host=COPAW_IP, port=COPAW_PORT)
# 检查服务是否可用
if not client.check_server():
print("[ERROR] CoPaw API 服务未运行!")
exit(1)
# ==================== 流式示例(实时输出) ====================
print("\n【流式模式 - 实时打印】")
# 测试消息内容
content = "你好,测试普通响应"
# 打印提示,不换行
print("AI 回复:", end="", flush=True)
full_text = "" # 用于累加完整回复
# 迭代获取实时流数据
for chunk in client.send_message_by_session(
user_id=USER_ID,
channel=CHANNEL,
session_id=SESSION_ID,
content=content,
stream=True
):
# 提取文本内容
for content_item in chunk.get("content", []):
if content_item.get("type") == "text":
text = content_item.get("text", "")
full_text += text
# 实时打印!end="" 避免换行,flush=True 强制立即输出
print(text, end="", flush=True)
print("\n\n【接收完成】")
# print(f"完整回复:{full_text}")
# ==================== 非流式示例 ====================
# 取消注释可测试非流式模式
# print("\n【非流式模式】")
# result = client.send_message_by_session(
# session_id=SESSION_ID,
# content="你好,测试普通响应",
# stream=False
# )
# print(f"回复:{result['text']}")
源码关键注释说明
| 代码段 | 关键注释 | 作用 |
|---|---|---|
from typing import Union |
兼容 Python < 3.10 | 替代 ` |
requests.Session() |
保持连接 | 复用 TCP 连接,提高性能 |
x-agent-id 请求头 |
标识目标 Agent | CoPaw 多 Agent 路由 |
stream=stream |
启用流式接收 | 配合 SSE 协议实现实时输出 |
iter_lines() |
逐行读取 | 避免一次性加载大响应 |
yield data |
生成器 | 边接收边返回,实现流式 |
sys.stdout.reconfigure(encoding='utf-8') |
UTF-8 输出 | 解决 Windows 控制台 emoji 编码问题 |
end="", flush=True |
实时打印 | 打字机效果的关键 |
timeout=1200 |
长超时 | 适应复杂任务(20 分钟) |
params={"chat_id": chat_id} |
查询参数 | 停止会话时传递 chat_id |
作者: 文档 99% 由 Copaw 生成
更新时间: 2026-04-10
Python 版本: 3.8+