DataWorks Python 节点调用 OpenAI API Demo
这个 demo 演示链路:
text
MaxCompute 输入表
-> DataWorks Python 节点读取待处理数据
-> Python 标准库 urllib 调用 OpenAI Responses API
-> 结果写回 MaxCompute 结果表
-> BI / SQL / 下游任务继续使用
1. 创建 MaxCompute 表
在 DataWorks 的 MaxCompute SQL 节点或临时查询中执行:
sql
-- 输入表:待处理文本
CREATE TABLE IF NOT EXISTS dw_openai_task_input (
id STRING COMMENT '业务主键',
content STRING COMMENT '待处理文本'
)
PARTITIONED BY (
ds STRING COMMENT '业务日期分区,格式 yyyyMMdd'
);
-- 结果表:OpenAI 处理结果
CREATE TABLE IF NOT EXISTS dw_openai_task_result (
id STRING COMMENT '业务主键',
source_content STRING COMMENT '原始文本',
model STRING COMMENT '调用模型',
result_text STRING COMMENT '模型输出',
raw_response STRING COMMENT '原始响应 JSON',
status STRING COMMENT 'SUCCESS / FAILED',
error_message STRING COMMENT '失败原因',
processed_at STRING COMMENT '处理时间,北京时间'
)
PARTITIONED BY (
ds STRING COMMENT '业务日期分区,格式 yyyyMMdd'
);
-- Demo 测试数据
INSERT OVERWRITE TABLE dw_openai_task_input PARTITION (ds = '20260616')
SELECT 'task_001', '客户反馈:物流太慢,包装破损,希望尽快补发。'
UNION ALL
SELECT 'task_002', '客户咨询:这个商品是否支持七天无理由退货?'
UNION ALL
SELECT 'task_003', '客户投诉:客服回复不及时,要求升级处理。';
表含义:
dw_openai_task_input: 待处理文本。dw_openai_task_result: OpenAI 处理结果。
2. 配置 DataWorks Python 节点参数
建议在 DataWorks 运维中心、调度参数或安全参数中配置:
| 参数 | 示例 | 说明 |
|---|---|---|
openai_api_key |
sk-... |
OpenAI API Key,不要写死在代码里 |
bizdate |
20260616 |
业务分区日期,调度时可用 DataWorks 日期变量替换 |
openai_model |
gpt-5.5 |
可按账号可用模型调整 |
如果 DataWorks 环境允许环境变量,也可以设置 OPENAI_API_KEY。
3. 创建 Python 节点
把 python/dataworks_openai_node.py 的内容复制到 DataWorks Python 节点。
python
# -*- coding: utf-8 -*-
"""
DataWorks Python 节点 Demo
这个脚本演示一条完整的数据处理链路:
1. 从 MaxCompute 输入表读取待处理文本。
2. 在 Python 节点中逐条调用 OpenAI Responses API。
3. 把每条 API 返回结果先暂存在内存列表里。
4. 达到批量阈值后,再批量写回 MaxCompute 结果表。
为什么要批量写回:
- OpenAI API 仍然需要逐条调用,因为每一行文本都是一次独立分析。
- MaxCompute 不建议每处理一行就 INSERT 一次,否则容易产生大量小文件。
- 所以这里采用"逐条调用 API,批量写结果表"的方式。
运行前提:
1. DataWorks PyODPS Python 节点通常会提供全局 ODPS 客户端对象 `o`。
2. 在 DataWorks 节点参数中配置:
- bizdate: 业务日期分区,例如 20260617。
- openai_api_key: OpenAI API Key。
- openai_model: 要调用的模型名称。
"""
# datetime: 生成处理时间。
# json: 组装 OpenAI 请求体、解析 OpenAI API 返回。
# os: 读取环境变量,方便本地测试或企业网关环境覆盖配置。
# time: 做请求重试等待、API 调用间隔限流。
# traceback: 失败时记录完整异常堆栈,方便排查问题。
# urllib: 使用 Python 标准库发 HTTP 请求,避免 DataWorks 环境额外安装 openai SDK。
import datetime
import json
import os
import time
import traceback
import urllib.error
import urllib.request
# 输入表:存放待处理数据。
# 期望字段:
# - id: 业务主键。
# - content: 待处理文本。
# - ds: 分区字段,格式通常为 yyyyMMdd。
INPUT_TABLE = "dw_openai_task_input"
# 结果表:存放 OpenAI 返回结果、执行状态和错误信息。
# 字段顺序需要和 sql/01_tables.sql 中的结果表保持一致。
RESULT_TABLE = "dw_openai_task_result"
# DataWorks 会在节点运行前把 ${bizdate} 替换成实际调度参数。
# 例如调度日期是 20260617,这里运行时就会变成 "20260617"。
BIZDATE = "${bizdate}"
# API Key 获取逻辑:
# 1. 优先从环境变量 OPENAI_API_KEY 读取,方便本地测试或安全托管。
# 2. 如果环境变量没有值,则使用 DataWorks 参数 ${openai_api_key}。
# 注意:生产环境不要把 API Key 明文写死在代码里。
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY") or "${openai_api_key}"
# 模型名称由 DataWorks 参数控制。
# 这样后续切换模型时,只需要改节点参数,不需要改代码。
OPENAI_MODEL = "${openai_model}" or "gpt-5.5"
# OpenAI API 地址。
# 默认使用官方地址;如果企业内部通过代理、网关或中转服务访问,可以用环境变量 OPENAI_BASE_URL 覆盖。
OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1")
# 单次节点最多处理多少行。
# 作用:控制单次调度规模,避免一次处理太多数据导致 DataWorks 节点超时。
MAX_ROWS_PER_RUN = int(os.environ.get("MAX_ROWS_PER_RUN", "100"))
# 单次 OpenAI API 请求超时时间。
# 作用:网络异常时不要一直阻塞在请求上。
REQUEST_TIMEOUT_SECONDS = int(os.environ.get("REQUEST_TIMEOUT_SECONDS", "60"))
# OpenAI API 请求失败后的最大重试次数。
# 主要用于处理 429 限流、5xx 临时服务异常等可重试错误。
MAX_RETRIES = int(os.environ.get("MAX_RETRIES", "3"))
# 每处理一行后暂停的秒数。
# 作用:降低高频请求触发 API 限流的概率。
SLEEP_SECONDS_BETWEEN_CALLS = float(os.environ.get("SLEEP_SECONDS_BETWEEN_CALLS", "0.2"))
# 批量写入阈值。
# 作用:每积累多少条处理结果,就批量写入一次 MaxCompute。
# 例如默认 100,表示每处理完 100 条结果写一次结果表。
BATCH_WRITE_SIZE = int(os.environ.get("BATCH_WRITE_SIZE", "100"))
def now_bj():
"""
返回北京时间字符串。
用途:
- 写入结果表 processed_at 字段。
- 方便后续排查每条记录是什么时候被处理的。
"""
return (datetime.datetime.utcnow() + datetime.timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")
def is_unresolved_placeholder(value):
"""
判断 DataWorks 参数是否没有被替换。
例如:
- 正常情况:BIZDATE = "20260617"
- 异常情况:BIZDATE = "${bizdate}"
如果参数仍然是 ${xxx},说明节点参数没有配置成功,脚本应该主动失败。
"""
return not value or (value.startswith("${") and value.endswith("}"))
def sql_string(value):
"""
把 Python 值转换成 MaxCompute SQL 里可用的字符串。
作用:
1. Python None 转成 SQL NULL。
2. 普通字符串加单引号。
3. 对反斜杠和单引号做转义,避免 SQL 拼接失败。
这个函数主要用于拼接查询输入表的 SQL。
批量写结果表时使用 open_writer,不需要拼接每个字段的 SQL 字符串。
"""
if value is None:
return "NULL"
return "'" + str(value).replace("\\", "\\\\").replace("'", "\\'") + "'"
def fetch_pending_rows(odps):
"""
从 MaxCompute 输入表读取本次需要处理的数据。
参数:
- odps: DataWorks PyODPS 节点内置的 ODPS 客户端对象,通常就是全局变量 `o`。
读取逻辑:
1. 只读取当前 bizdate 分区,避免跨天误处理。
2. 排除结果表里已经 SUCCESS 的 id,实现简单断点续跑。
3. 使用 LIMIT 控制本次最多处理 MAX_ROWS_PER_RUN 条。
返回:
- rows: Python 列表,每个元素是 {"id": ..., "content": ...}。
"""
# 这里使用 SELECT 查询待处理数据。
# NOT IN 子查询用于跳过已经成功处理过的数据。
sql = """
SELECT id, content
FROM {input_table}
WHERE ds = {ds}
AND id NOT IN (
SELECT id
FROM {result_table}
WHERE ds = {ds}
AND status = 'SUCCESS'
)
LIMIT {limit}
""".format(
input_table=INPUT_TABLE,
result_table=RESULT_TABLE,
ds=sql_string(BIZDATE),
limit=MAX_ROWS_PER_RUN,
)
# execute_sql 执行 MaxCompute SQL。
# open_reader 打开结果读取器。
# record[0] 对应 SELECT 的第一个字段 id。
# record[1] 对应 SELECT 的第二个字段 content。
rows = []
with odps.execute_sql(sql).open_reader() as reader:
for record in reader:
rows.append({"id": record[0], "content": record[1]})
return rows
def extract_output_text(response_obj):
"""
从 OpenAI Responses API 的 JSON 返回里提取模型最终文本。
参数:
- response_obj: json.loads(raw_response) 得到的 Python dict。
提取逻辑:
1. 如果响应里有 output_text,优先直接返回。
2. 如果没有 output_text,则从 output -> content 结构里兜底提取 text。
返回:
- 模型输出文本,通常是符合 json_schema 的 JSON 字符串。
"""
# 常见情况:Responses API 直接返回 output_text。
if response_obj.get("output_text"):
return response_obj["output_text"]
# 兜底情况:从 output 数组里逐层找文本内容。
texts = []
for item in response_obj.get("output", []):
for content in item.get("content", []):
if content.get("type") in ("output_text", "text") and content.get("text"):
texts.append(content["text"])
# 如果有多段文本,就用换行拼接。
return "\n".join(texts)
def call_openai(content):
"""
调用 OpenAI Responses API 分析单条文本。
参数:
- content: MaxCompute 输入表中的原始文本。
返回两个值:
- result_text: 从 OpenAI 响应中提取出的模型最终文本。
- raw_response: OpenAI API 返回的完整原始 JSON 字符串。
为什么返回 raw_response:
- 方便审计。
- 方便排查模型输出、token、错误信息等细节。
"""
# 拼接 Responses API endpoint。
# 如果 OPENAI_BASE_URL = https://api.openai.com/v1
# 最终 url = https://api.openai.com/v1/responses
url = OPENAI_BASE_URL.rstrip("/") + "/responses"
# 组装请求体 payload。
# model: 使用哪个模型。
# input: 对话输入,包含 system 和 user。
# text.format: 要求模型按 json_schema 输出,便于下游 SQL/BI 解析。
payload = {
"model": OPENAI_MODEL,
"input": [
{
"role": "system",
"content": "你是电商客服数据分析助手。请用 JSON 输出 sentiment、category、summary、suggested_action。",
},
{
"role": "user",
"content": content,
},
],
"text": {
"format": {
"type": "json_schema",
"name": "customer_ticket_analysis",
"schema": {
"type": "object",
"additionalProperties": False,
"properties": {
"sentiment": {"type": "string"},
"category": {"type": "string"},
"summary": {"type": "string"},
"suggested_action": {"type": "string"},
},
"required": ["sentiment", "category", "summary", "suggested_action"],
},
}
},
}
# 把 Python dict 转成 JSON 字符串,再编码成 UTF-8 bytes。
# ensure_ascii=False 可以保留中文,不把中文转成 \uXXXX。
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
# 构造 HTTP POST 请求。
# Authorization: Bearer + API Key。
# Content-Type: application/json 表示请求体是 JSON。
req = urllib.request.Request(
url,
data=data,
headers={
"Authorization": "Bearer " + OPENAI_API_KEY,
"Content-Type": "application/json",
},
method="POST",
)
# 执行请求,并增加重试。
# attempt 从 1 开始,到 MAX_RETRIES 结束。
for attempt in range(1, MAX_RETRIES + 1):
try:
# urlopen 真正发起 HTTP 请求。
# timeout 防止请求长时间挂住。
with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as resp:
# raw 是 API 返回的原始 JSON 字符串。
raw = resp.read().decode("utf-8")
# obj 是把 JSON 字符串解析后的 Python dict。
obj = json.loads(raw)
# 返回模型最终文本和原始响应。
return extract_output_text(obj), raw
except urllib.error.HTTPError as exc:
# HTTPError 表示服务端返回了非 2xx 状态码。
# 读取 body 是为了把错误详情写到失败原因里。
body = exc.read().decode("utf-8", errors="replace")
# 429: 限流。
# 5xx: 服务端或网关临时异常。
# 这些错误可以重试。
if exc.code in (429, 500, 502, 503, 504) and attempt < MAX_RETRIES:
time.sleep(2 ** attempt)
continue
# 不可重试,或已经达到最大重试次数,抛出异常交给 main 记录失败。
raise RuntimeError("OpenAI HTTP {0}: {1}".format(exc.code, body))
except Exception:
# 网络超时、连接失败等其他异常也允许重试。
if attempt < MAX_RETRIES:
time.sleep(2 ** attempt)
continue
# 最后一次仍失败,则抛出异常交给 main 记录失败。
raise
def build_result_row(row_id, source_content, result_text, raw_response, status, error_message):
"""
组装一行准备写入 MaxCompute 结果表的数据。
参数:
- row_id: 输入表 id。
- source_content: 原始文本。
- result_text: 模型最终输出。
- raw_response: OpenAI 原始响应。
- status: SUCCESS 或 FAILED。
- error_message: 失败原因,成功时为空字符串。
注意:
返回列表的字段顺序必须和结果表非分区字段顺序一致:
id, source_content, model, result_text, raw_response,
status, error_message, processed_at
"""
return [
row_id,
source_content,
OPENAI_MODEL,
result_text,
raw_response,
status,
error_message,
now_bj(),
]
def write_results_batch(odps, result_rows):
"""
批量写入 MaxCompute 结果表。
参数:
- odps: DataWorks PyODPS 节点内置的 ODPS 客户端对象。
- result_rows: 待写入结果列表,每个元素是一行结果表数据。
为什么不用每条 INSERT:
- 每条 INSERT 都会提交一次 SQL。
- 大量小批次写入容易产生小文件。
- 下游查询和存储管理都会受影响。
这里使用 table.open_writer:
- 一次 writer.write(result_rows) 写入多行。
- create_partition=True 表示分区不存在时自动创建。
"""
if not result_rows:
print("No result rows to write.")
return
# 获取 MaxCompute 结果表对象。
table = odps.get_table(RESULT_TABLE)
# 指定写入哪个分区,例如 ds=20260617。
partition = "ds={0}".format(BIZDATE)
# open_writer 打开表写入器。
# writer.write(result_rows) 会按照表字段顺序批量写入数据。
with table.open_writer(partition=partition, create_partition=True) as writer:
writer.write(result_rows)
print("Batch written rows: {0}".format(len(result_rows)))
def main(odps):
"""
主流程入口。
完整执行步骤:
1. 检查 DataWorks 参数是否已经正确替换。
2. 从 MaxCompute 输入表读取待处理数据。
3. 逐条调用 OpenAI API。
4. 将成功或失败结果放入 result_rows。
5. result_rows 达到 BATCH_WRITE_SIZE 后批量写入。
6. 循环结束后,把最后不足一个批次的剩余数据写入。
"""
# 参数检查:bizdate 必须由 DataWorks 参数替换成功。
if is_unresolved_placeholder(BIZDATE):
raise ValueError("Missing DataWorks parameter: bizdate")
# 参数检查:API Key 必须来自环境变量或 DataWorks 参数。
if is_unresolved_placeholder(OPENAI_API_KEY):
raise ValueError("Missing DataWorks parameter or env var: openai_api_key / OPENAI_API_KEY")
# 参数检查:模型名称必须配置。
if is_unresolved_placeholder(OPENAI_MODEL):
raise ValueError("Missing DataWorks parameter: openai_model")
# 第一步:读取待处理数据。
rows = fetch_pending_rows(odps)
print("Pending rows: {0}".format(len(rows)))
# result_rows 用来暂存本批次准备写入结果表的数据。
# 这样不会每处理一条就写一次 MaxCompute。
result_rows = []
# 第二步:逐条处理输入数据。
# 这里仍然逐条调用 OpenAI,因为每条 content 都是独立分析任务。
for row in rows:
row_id = row["id"]
content = row["content"]
try:
# 第三步:调用 OpenAI 获取分析结果。
result_text, raw_response = call_openai(content)
# 第四步:成功结果不立刻写表,而是先加入 result_rows。
result_rows.append(build_result_row(row_id, content, result_text, raw_response, "SUCCESS", ""))
print("SUCCESS id={0}".format(row_id))
except Exception as exc:
# 如果当前行失败,不让它影响其他行。
# 记录失败原因和完整堆栈,后续可以按 status=FAILED 排查。
err = "{0}\n{1}".format(str(exc), traceback.format_exc())
# 失败结果也加入 result_rows,和成功结果一起批量写入。
result_rows.append(build_result_row(row_id, content, "", "", "FAILED", err[:4000]))
print("FAILED id={0}, error={1}".format(row_id, str(exc)))
# 第五步:达到批量阈值后,批量写入结果表。
# 写完后清空 result_rows,继续积累下一批。
if len(result_rows) >= BATCH_WRITE_SIZE:
write_results_batch(odps, result_rows)
result_rows = []
# 简单限流:避免请求过快导致 OpenAI API 返回 429。
if SLEEP_SECONDS_BETWEEN_CALLS > 0:
time.sleep(SLEEP_SECONDS_BETWEEN_CALLS)
# 第六步:循环结束后,把不足一个批次的剩余结果写入结果表。
write_results_batch(odps, result_rows)
# DataWorks PyODPS 节点里一般会内置全局变量 o,代表当前 MaxCompute 连接。
# 如果你们项目的 ODPS 客户端变量不是 o,把这里替换成实际变量名即可。
main(o)
脚本默认依赖 DataWorks PyODPS 节点提供的全局变量 o。如果你们项目里的 ODPS 客户端变量名不同,可以把脚本底部的:
python
main(o)
改成实际变量名。
4. 验证结果
运行 Python 节点后查询:
sql
SELECT *
FROM dw_openai_task_result
WHERE ds = '20260616'
ORDER BY id;
SELECT *
, GET_JSON_OBJECT(result_text, '$.category') AS category
, GET_JSON_OBJECT(result_text, '$.sentiment') AS sentiment
, GET_JSON_OBJECT(result_text, '$.suggested_action') AS suggested_action
, GET_JSON_OBJECT(result_text, '$.summary') AS summary
FROM dw_openai_task_result WHERE ds = '20260616'
;
数据样例查询:
sql
SELECT * FROM bigdata_dev.tmp_dw_openai_task_input WHERE ds = '20260616';
| id | content | ds |
|---|---|---|
| task_001 | 客户反馈:物流太慢,包装破损,希望尽快补发。 | 20260616 |
| task_002 | 客户咨询:这个商品是否支持七天无理由退货? | 20260616 |
| task_003 | 客户投诉:客服回复不及时,要求升级处理。 | 20260616 |
| task_004 | 客户咨询:这个商品是否退货包运费?。 | 20260616 |
| task_005 | 客户反馈:这个吸尘器很好用,吸力很大,打扫干净。 | 20260616 |
sql
SELECT * FROM bigdata_dev.tmp_dw_openai_task_result WHERE ds = '20260616';
| id | source_content | model | result_text | raw_response | status | error_message | processed_at | ds |
|---|---|---|---|---|---|---|---|---|
| task_001 | 客户反馈:物流太慢,包装破损,希望尽快补发。 | gpt-5.5 | {"category":"物流/包装/补发请求","sentiment":"负面","suggested_action":"立即核查物流状态和包裹破损情况,向客户致歉并优先安排补发;同时提供新的物流单号和预计送达时间,必要时给予优惠券或补偿。","summary":"客户投诉物流速度慢且收到的包装破损,要求尽快补发商品。"} | {"id":"resp_nB-H0stQEK7Q3tr9B5mK9dz9uuCaTYHeFHBzhXPVm8Snri6e7LDWPMrXhqrPLr4O6MZ4lSpcyZLFVfcUB3q-_trEmfyfahEZKVEp-XLx2hQIfrV-71aEmHWATYh5h95zQCyoVNZkBUfmq41S2Q6AvC2BjrOoqNlw_M8qf0PK9fF4iQsWNxq4c94QQWpwJ5hkbejp2wXEfXrsFj3aGnQzLo8hPw64o305_uQWPS4xUDTORXDfaeW79K51j6OZT21NgJYrzRHuQUSoVxa8HEWfietEtVq-kBwloQBUzjY-0M43z8mjbPRxwtvNpHE-MH00NoONW7IVi_nv1kP4yzzDBbjaTBfsGD5mAAJX61yPlPmACfhxHoROegG9vuTuO_93qXcOeJacWYazycztBrHjJGzCHx5tRk45uJQI3bNPOaJMYpmP_3NGLdKowsM5uaT8qV5o5sFMiEiamhLFIryMrhcHQCtE4sKolTV8dDqQug4cLTM_RjO7","created_at":1781683965,"error":null,"incomplete_details":null,"instructions":"You are Codex, based on GPT-5. You are running as a coding agent in the Codex CLI on a user's computer.\n\n## General\n\n- When searching for text or files, prefer using rg or rg --files respectively because rg is much faster than alternatives like grep. (If the rg command is not found, then use alternatives.)\n\n## Editing constraints\n\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\n- Add succinct code comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare.\n- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).\n- You may be in a dirty git worktree.\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes.\n * If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them.\n * If the changes are in unrelated files, just ignore them and don't revert them.\n- Do not amend a commit unless explicitly requested to do so.\n- While you are working, you might notice unexpected changes that you didn't make. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed.\n- NEVER use destructive commands like git reset --hard or git checkout -- unless specifically requested or approved by the user.\n\n## Plan tool\n\nWhen using the planning tool:\n- Skip using the planning tool for straightforward tasks (roughly the easiest 25%).\n- Do not make single-step plans.\n- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan.\n\n## Special user requests\n\n- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as date), you should do so.\n- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.\n\n## Presenting your work and final message\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n- Default: be very concise; friendly coding teammate tone.\n- Ask only when needed; suggest ideas; mirror the user's style.\n- For substantial work, summarize clearly; follow final‑answer formatting.\n- Skip heavy formatting for simple confirmations.\n- Don't dump large files you've written; reference paths only.\n- No "save/copy this file" - User is on the same machine.\n- Offer logical next steps (tests, commits, build) briefly; add verify steps if you couldn't do something.\n- For code changes:\n * Lead with a quick explanation of the change, and then give more details on the context covering where and why a change was made. Do not start this explanation with "summary", just jump right in.\n * If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps.\n * When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number.\n- The user does not command execution outputs. When asked to show the output of a command (e.g. git show), relay the important details in your answer or summarize the key lines so the user understands the result.\n\n### Final answer structure and style guidelines\n\n- Plain text; CLI handles styling. Use structure only when it helps scanability.\n- Headers: optional; short Title Case (1-3 words) wrapped in ...; no blank line before the first bullet; add only if they truly help.\n- Bullets: use - ; merge related points; keep to one line when possible; 4--6 per list ordered by importance; keep phrasing consistent.\n- Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.\n- Code samples or multi-line snippets should be wrapped in fenced code blocks; include an info string as often as possible.\n- Structure: group related bullets; order sections general → specific → supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.\n- Tone: collaborative, concise, factual; present tense, active voice; self‑contained; no "above/below"; parallel wording.\n- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short---wrap/reformat if long; avoid naming formatting styles in answers.\n- Adaptation: code explanations → precise, structured with code refs; simple tasks → lead with outcome; big changes → logical walkthrough + rationale + next actions; casual one-offs → plain sentences, no headers/bullets.\n- File References: When referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspace‑relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1‑based, optional): :line:column or #LlineCcolumn (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repo\project\main.rs:12:5\n\n","metadata":{},"model":"gpt-5.5","object":"response","output":{"id":"msg_070d32e241115f60016a3256fee91c8190b79ab820b7453971","content":\[{"annotations":\[,"text":"{"category":"物流/包装/补发请求","sentiment":"负面","suggested_action":"立即核查物流状态和包裹破损情况,向客户致歉并优先安排补发;同时提供新的物流单号和预计送达时间,必要时给予优惠券或补偿。","summary":"客户投诉物流速度慢且收到的包装破损,要求尽快补发商品。"}","type":"output_text","logprobs":\[\]}],"role":"assistant","status":"completed","type":"message","phase":"final_answer"}],"parallel_tool_calls":true,"temperature":1.0,"tool_choice":"auto","tools":\[\],"top_p":0.98,"max_output_tokens":null,"previous_response_id":null,"reasoning":{"context":"current_turn","effort":"medium","summary":"detailed"},"status":"completed","text":{"format":{"description":null,"name":"customer_ticket_analysis","schema":{"additionalProperties":false,"properties":{"category":{"type":"string"},"sentiment":{"type":"string"},"suggested_action":{"type":"string"},"summary":{"type":"string"}},"required":"sentiment","category","summary","suggested_action","type":"object"},"strict":true,"type":"json_schema"},"verbosity":"medium"},"truncation":"disabled","usage":{"input_tokens":1536,"input_tokens_details":{"audio_tokens":null,"cached_tokens":0,"text_tokens":null},"output_tokens":98,"output_tokens_details":{"reasoning_tokens":0,"text_tokens":null},"total_tokens":1634,"cost":null},"user":null,"store":false,"background":false,"completed_at":1781683968,"frequency_penalty":0,"max_tool_calls":null,"moderation":null,"presence_penalty":0,"prompt_cache_key":"bb24d301e716a716","prompt_cache_retention":"24h","safety_identifier":"user-ebptkCFuyAwqwTclcwTAZGyL","service_tier":"default","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"top_logprobs":0} |
SUCCESS | 2026-06-17 16:12:48 | 20260616 | |
| task_004 | 客户咨询:这个商品是否退货包运费?。 | gpt-5.5 | {"category":"退货运费政策咨询","sentiment":"中性","suggested_action":"告知客户该商品是否支持退货包运费,说明适用条件、退货流程及运费赔付方式;如需确认具体商品政策,请引导客户提供订单号或商品链接。","summary":"客户咨询该商品退货时是否包运费。"} | {"id":"resp_VS5lCqQE2y5CAQy8Xd4b-Vr4ZsQOrIIPJ1Dy00h8zN4WqUDJPHTAquIxaGeebUNcKjzBnczeuddQl3TVGmeGzv5c1e4GOJCpf3Uux_CADPY8ozOEdTlUcvjLcutqLRzabpgodqAeAkJOBYnY1NCkgvUV90iO0lPdfobbRSIPPWWkI07I-LmAanIDegmDhOH2Qwa_XpZ2HxqEpo1TJpQTX-bzFHIF6zz6q7ZSYdg2PupNFyeU0ZRsD0_SxK0tyGuYxMfUUF3KRBC_TrEM2JWGFXsqNZ9E42DtNVy6w90hyVjqjcOoWFSTFf13nkSfwTxEVaV2WrhiY8JSgKjozRLKBqt0tCv0VlAUESqeNpyksBbd5ay7G7zAfIi_dwgO0Vct13RoK1CMQvQsO6f7bY71dromKQASBbJSb6pe_HuckJ_QpdR54-dw8OFD2Cps9kZcnq8vCQlXo14ZNomGN8bY_ASg6SnMzcW4q_XXnUtNqxXCkBEZO6KI","created_at":1781685828,"error":null,"incomplete_details":null,"instructions":"You are Codex, based on GPT-5. You are running as a coding agent in the Codex CLI on a user's computer.\n\n## General\n\n- When searching for text or files, prefer using rg or rg --files respectively because rg is much faster than alternatives like grep. (If the rg command is not found, then use alternatives.)\n\n## Editing constraints\n\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\n- Add succinct code comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare.\n- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).\n- You may be in a dirty git worktree.\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes.\n * If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them.\n * If the changes are in unrelated files, just ignore them and don't revert them.\n- Do not amend a commit unless explicitly requested to do so.\n- While you are working, you might notice unexpected changes that you didn't make. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed.\n- NEVER use destructive commands like git reset --hard or git checkout -- unless specifically requested or approved by the user.\n\n## Plan tool\n\nWhen using the planning tool:\n- Skip using the planning tool for straightforward tasks (roughly the easiest 25%).\n- Do not make single-step plans.\n- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan.\n\n## Special user requests\n\n- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as date), you should do so.\n- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.\n\n## Presenting your work and final message\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n- Default: be very concise; friendly coding teammate tone.\n- Ask only when needed; suggest ideas; mirror the user's style.\n- For substantial work, summarize clearly; follow final‑answer formatting.\n- Skip heavy formatting for simple confirmations.\n- Don't dump large files you've written; reference paths only.\n- No "save/copy this file" - User is on the same machine.\n- Offer logical next steps (tests, commits, build) briefly; add verify steps if you couldn't do something.\n- For code changes:\n * Lead with a quick explanation of the change, and then give more details on the context covering where and why a change was made. Do not start this explanation with "summary", just jump right in.\n * If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps.\n * When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number.\n- The user does not command execution outputs. When asked to show the output of a command (e.g. git show), relay the important details in your answer or summarize the key lines so the user understands the result.\n\n### Final answer structure and style guidelines\n\n- Plain text; CLI handles styling. Use structure only when it helps scanability.\n- Headers: optional; short Title Case (1-3 words) wrapped in ...; no blank line before the first bullet; add only if they truly help.\n- Bullets: use - ; merge related points; keep to one line when possible; 4--6 per list ordered by importance; keep phrasing consistent.\n- Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.\n- Code samples or multi-line snippets should be wrapped in fenced code blocks; include an info string as often as possible.\n- Structure: group related bullets; order sections general → specific → supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.\n- Tone: collaborative, concise, factual; present tense, active voice; self‑contained; no "above/below"; parallel wording.\n- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short---wrap/reformat if long; avoid naming formatting styles in answers.\n- Adaptation: code explanations → precise, structured with code refs; simple tasks → lead with outcome; big changes → logical walkthrough + rationale + next actions; casual one-offs → plain sentences, no headers/bullets.\n- File References: When referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspace‑relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1‑based, optional): :line:column or #LlineCcolumn (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repo\project\main.rs:12:5\n\n","metadata":{},"model":"gpt-5.5","object":"response","output":{"id":"msg_07eab07151869513016a325e47989c8194ba1f7ef3970f984d","content":\[{"annotations":\[,"text":"{"category":"退货运费政策咨询","sentiment":"中性","suggested_action":"告知客户该商品是否支持退货包运费,说明适用条件、退货流程及运费赔付方式;如需确认具体商品政策,请引导客户提供订单号或商品链接。","summary":"客户咨询该商品退货时是否包运费。"}","type":"output_text","logprobs":\[\]}],"role":"assistant","status":"completed","type":"message","phase":"final_answer"}],"parallel_tool_calls":true,"temperature":1.0,"tool_choice":"auto","tools":\[\],"top_p":0.98,"max_output_tokens":null,"previous_response_id":null,"reasoning":{"context":"current_turn","effort":"medium","summary":"detailed"},"status":"completed","text":{"format":{"description":null,"name":"customer_ticket_analysis","schema":{"additionalProperties":false,"properties":{"category":{"type":"string"},"sentiment":{"type":"string"},"suggested_action":{"type":"string"},"summary":{"type":"string"}},"required":"sentiment","category","summary","suggested_action","type":"object"},"strict":true,"type":"json_schema"},"verbosity":"medium"},"truncation":"disabled","usage":{"input_tokens":1533,"input_tokens_details":{"audio_tokens":null,"cached_tokens":0,"text_tokens":null},"output_tokens":90,"output_tokens_details":{"reasoning_tokens":0,"text_tokens":null},"total_tokens":1623,"cost":null},"user":null,"store":false,"background":false,"completed_at":1781685833,"frequency_penalty":0,"max_tool_calls":null,"moderation":null,"presence_penalty":0,"prompt_cache_key":"b5fea27a3542c9ec","prompt_cache_retention":"24h","safety_identifier":"user-BsN2nRZlykyUiPfvuLcsIu22","service_tier":"default","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"top_logprobs":0} |
SUCCESS | 2026-06-17 16:46:21 | 20260616 | |
| task_005 | 客户反馈:这个吸尘器很好用,吸力很大,打扫干净。 | gpt-5.5 | {"category":"产品表扬","sentiment":"正面","suggested_action":"感谢客户反馈,可邀请客户进行公开评价或晒单,并推荐相关配件/耗材以提升复购。","summary":"客户对吸尘器使用体验满意,认可其吸力强、清洁效果好。"} | {"id":"resp_Pib7KqK9KvVGwD3TJD-vhnjj4-3W3mFhXkB00aoNOVv1vu6t3WYI8SjOED0cuIBQdF7FMECBJWtOEgZbGClO4Fh42fnJNY_ZpETPdBHY2k_af3nTZdemnKNUszgXb5CT3s123tvlnxGfnw32nR6gQCQDdqLqOIZK48IMPuUJuNeEzrMND_osL5YVWexav8gSvNBgbrXNnCqVICChG1y0s61PruZPaGX1fgDxwVHBX1_A16mQkBUW1Io633H3gc0k-BcWn7x7zfi_4Up1O-oiD-ycIxgOEc8EM14PoG0wnwldvsyWDLhKj761Lde4bMeLSwzyTsyc67HBQsrWGWhRHGp0ghFZhxx7mSbPWVR8SUKt6_AJAmSBvJalpf081QAfGjfyMGKvQMv92CxU1YjC9-vkXjWDPCryn3y0XO95UeNrRDkLiE7fEm5LsZ9blLKwK9YFIQ7ocmDL4Dc_QExcj_ZlMsSSZTn7X1zNkHWk2VvJEyyI2v4t","created_at":1781685982,"error":null,"incomplete_details":null,"instructions":"You are Codex, based on GPT-5. You are running as a coding agent in the Codex CLI on a user's computer.\n\n## General\n\n- When searching for text or files, prefer using rg or rg --files respectively because rg is much faster than alternatives like grep. (If the rg command is not found, then use alternatives.)\n\n## Editing constraints\n\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\n- Add succinct code comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare.\n- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).\n- You may be in a dirty git worktree.\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes.\n * If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them.\n * If the changes are in unrelated files, just ignore them and don't revert them.\n- Do not amend a commit unless explicitly requested to do so.\n- While you are working, you might notice unexpected changes that you didn't make. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed.\n- NEVER use destructive commands like git reset --hard or git checkout -- unless specifically requested or approved by the user.\n\n## Plan tool\n\nWhen using the planning tool:\n- Skip using the planning tool for straightforward tasks (roughly the easiest 25%).\n- Do not make single-step plans.\n- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan.\n\n## Special user requests\n\n- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as date), you should do so.\n- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.\n\n## Presenting your work and final message\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n- Default: be very concise; friendly coding teammate tone.\n- Ask only when needed; suggest ideas; mirror the user's style.\n- For substantial work, summarize clearly; follow final‑answer formatting.\n- Skip heavy formatting for simple confirmations.\n- Don't dump large files you've written; reference paths only.\n- No "save/copy this file" - User is on the same machine.\n- Offer logical next steps (tests, commits, build) briefly; add verify steps if you couldn't do something.\n- For code changes:\n * Lead with a quick explanation of the change, and then give more details on the context covering where and why a change was made. Do not start this explanation with "summary", just jump right in.\n * If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps.\n * When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number.\n- The user does not command execution outputs. When asked to show the output of a command (e.g. git show), relay the important details in your answer or summarize the key lines so the user understands the result.\n\n### Final answer structure and style guidelines\n\n- Plain text; CLI handles styling. Use structure only when it helps scanability.\n- Headers: optional; short Title Case (1-3 words) wrapped in ...; no blank line before the first bullet; add only if they truly help.\n- Bullets: use - ; merge related points; keep to one line when possible; 4--6 per list ordered by importance; keep phrasing consistent.\n- Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.\n- Code samples or multi-line snippets should be wrapped in fenced code blocks; include an info string as often as possible.\n- Structure: group related bullets; order sections general → specific → supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.\n- Tone: collaborative, concise, factual; present tense, active voice; self‑contained; no "above/below"; parallel wording.\n- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short---wrap/reformat if long; avoid naming formatting styles in answers.\n- Adaptation: code explanations → precise, structured with code refs; simple tasks → lead with outcome; big changes → logical walkthrough + rationale + next actions; casual one-offs → plain sentences, no headers/bullets.\n- File References: When referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspace‑relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1‑based, optional): :line:column or #LlineCcolumn (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repo\project\main.rs:12:5\n\n","metadata":{},"model":"gpt-5.5","object":"response","output":{"id":"msg_0e34e6a64a66ab02016a325edf07648196b82dfe56a1d3337a","content":\[{"annotations":\[,"text":"{"category":"产品表扬","sentiment":"正面","suggested_action":"感谢客户反馈,可邀请客户进行公开评价或晒单,并推荐相关配件/耗材以提升复购。","summary":"客户对吸尘器使用体验满意,认可其吸力强、清洁效果好。"}","type":"output_text","logprobs":\[\]}],"role":"assistant","status":"completed","type":"message","phase":"final_answer"}],"parallel_tool_calls":true,"temperature":1.0,"tool_choice":"auto","tools":\[\],"top_p":0.98,"max_output_tokens":null,"previous_response_id":null,"reasoning":{"context":"current_turn","effort":"medium","summary":"detailed"},"status":"completed","text":{"format":{"description":null,"name":"customer_ticket_analysis","schema":{"additionalProperties":false,"properties":{"category":{"type":"string"},"sentiment":{"type":"string"},"suggested_action":{"type":"string"},"summary":{"type":"string"}},"required":"sentiment","category","summary","suggested_action","type":"object"},"strict":true,"type":"json_schema"},"verbosity":"medium"},"truncation":"disabled","usage":{"input_tokens":1541,"input_tokens_details":{"audio_tokens":null,"cached_tokens":0,"text_tokens":null},"output_tokens":75,"output_tokens_details":{"reasoning_tokens":0,"text_tokens":null},"total_tokens":1616,"cost":null},"user":null,"store":false,"background":false,"completed_at":1781685984,"frequency_penalty":0,"max_tool_calls":null,"moderation":null,"presence_penalty":0,"prompt_cache_key":"a1cf096cf4def8ec","prompt_cache_retention":"24h","safety_identifier":"user-JxCRkVRsM1YwbHeBfC5hBdHT","service_tier":"default","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"top_logprobs":0} |
SUCCESS | 2026-06-17 16:46:24 | 20260616 | |
| task_002 | 客户咨询:这个商品是否支持七天无理由退货? | gpt-5.5 | {"category":"退换货政策咨询","sentiment":"中性","suggested_action":"核实该商品类目和店铺退货规则,告知客户是否支持七天无理由退货;如支持,补充说明退货条件、时限、运费承担及申请路径。","summary":"客户询问该商品是否支持七天无理由退货。"} | {"id":"resp_l9dfDihFQxwBTSXkz_9LJ_a4LeJywGrB1Ah_JrdU_z2zBDeoaiR6F96i-CbreWzlgP51Sos_rdCO0psuJv9NOim-b4EemYYUE2VJgOxgFmpSqJT3xdVNyFPB8H9bi_lk_ICDCzGeFhnHsqYlUEy3LNzWdGwo1pfhn1M7OVbtzG4PM7GLGfyI_7x54JxS-rvGNAduXC5_4yoe44w9NHieQPEkBdgFQPs3-SXv_1iYU5ZR_BXIhpqJCIdBx3xq3vzNy-63HSieeFmLm4AL259UA1CYq0-EbCyxevan-L7rBKksZgq-xlhCBxcaHUuG58qShsO7UFe21O_WZ-cqdx65hsuxlfwMs788eQHqvEISP0VeKi0PR-oDW7sdk1_O4L923Q5B4R4m8TCktzt7Il86zIL8MUSyeHvK0kDGaFAMrbOugwqu0HycW3gQV60bEy30pf__05xfvV5koWDNbb6akUkfYmpIdRPLOYKERXysRynwGRAaHiHc","created_at":1781683972,"error":null,"incomplete_details":null,"instructions":"You are Codex, based on GPT-5. You are running as a coding agent in the Codex CLI on a user's computer.\n\n## General\n\n- When searching for text or files, prefer using rg or rg --files respectively because rg is much faster than alternatives like grep. (If the rg command is not found, then use alternatives.)\n\n## Editing constraints\n\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\n- Add succinct code comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare.\n- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).\n- You may be in a dirty git worktree.\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes.\n * If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them.\n * If the changes are in unrelated files, just ignore them and don't revert them.\n- Do not amend a commit unless explicitly requested to do so.\n- While you are working, you might notice unexpected changes that you didn't make. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed.\n- NEVER use destructive commands like git reset --hard or git checkout -- unless specifically requested or approved by the user.\n\n## Plan tool\n\nWhen using the planning tool:\n- Skip using the planning tool for straightforward tasks (roughly the easiest 25%).\n- Do not make single-step plans.\n- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan.\n\n## Special user requests\n\n- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as date), you should do so.\n- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.\n\n## Presenting your work and final message\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n- Default: be very concise; friendly coding teammate tone.\n- Ask only when needed; suggest ideas; mirror the user's style.\n- For substantial work, summarize clearly; follow final‑answer formatting.\n- Skip heavy formatting for simple confirmations.\n- Don't dump large files you've written; reference paths only.\n- No "save/copy this file" - User is on the same machine.\n- Offer logical next steps (tests, commits, build) briefly; add verify steps if you couldn't do something.\n- For code changes:\n * Lead with a quick explanation of the change, and then give more details on the context covering where and why a change was made. Do not start this explanation with "summary", just jump right in.\n * If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps.\n * When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number.\n- The user does not command execution outputs. When asked to show the output of a command (e.g. git show), relay the important details in your answer or summarize the key lines so the user understands the result.\n\n### Final answer structure and style guidelines\n\n- Plain text; CLI handles styling. Use structure only when it helps scanability.\n- Headers: optional; short Title Case (1-3 words) wrapped in ...; no blank line before the first bullet; add only if they truly help.\n- Bullets: use - ; merge related points; keep to one line when possible; 4--6 per list ordered by importance; keep phrasing consistent.\n- Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.\n- Code samples or multi-line snippets should be wrapped in fenced code blocks; include an info string as often as possible.\n- Structure: group related bullets; order sections general → specific → supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.\n- Tone: collaborative, concise, factual; present tense, active voice; self‑contained; no "above/below"; parallel wording.\n- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short---wrap/reformat if long; avoid naming formatting styles in answers.\n- Adaptation: code explanations → precise, structured with code refs; simple tasks → lead with outcome; big changes → logical walkthrough + rationale + next actions; casual one-offs → plain sentences, no headers/bullets.\n- File References: When referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspace‑relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1‑based, optional): :line:column or #LlineCcolumn (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repo\project\main.rs:12:5\n\n","metadata":{},"model":"gpt-5.5","object":"response","output":{"id":"msg_019e278695f9ca4b016a325708a7fc81959d8a8d7bc447bcb3","content":\[{"annotations":\[,"text":"{"category":"退换货政策咨询","sentiment":"中性","suggested_action":"核实该商品类目和店铺退货规则,告知客户是否支持七天无理由退货;如支持,补充说明退货条件、时限、运费承担及申请路径。","summary":"客户询问该商品是否支持七天无理由退货。"}","type":"output_text","logprobs":\[\]}],"role":"assistant","status":"completed","type":"message","phase":"final_answer"}],"parallel_tool_calls":true,"temperature":1.0,"tool_choice":"auto","tools":\[\],"top_p":0.98,"max_output_tokens":null,"previous_response_id":null,"reasoning":{"context":"current_turn","effort":"medium","summary":"detailed"},"status":"completed","text":{"format":{"description":null,"name":"customer_ticket_analysis","schema":{"additionalProperties":false,"properties":{"category":{"type":"string"},"sentiment":{"type":"string"},"suggested_action":{"type":"string"},"summary":{"type":"string"}},"required":"sentiment","category","summary","suggested_action","type":"object"},"strict":true,"type":"json_schema"},"verbosity":"medium"},"truncation":"disabled","usage":{"input_tokens":1534,"input_tokens_details":{"audio_tokens":null,"cached_tokens":0,"text_tokens":null},"output_tokens":91,"output_tokens_details":{"reasoning_tokens":0,"text_tokens":null},"total_tokens":1625,"cost":null},"user":null,"store":false,"background":false,"completed_at":1781683978,"frequency_penalty":0,"max_tool_calls":null,"moderation":null,"presence_penalty":0,"prompt_cache_key":"5b225023f65f36fe","prompt_cache_retention":"24h","safety_identifier":"user-HokxrDwMY7tOQgvHJ9diQR7M","service_tier":"default","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"top_logprobs":0} |
SUCCESS | 2026-06-17 16:12:58 | 20260616 | |
| task_003 | 客户投诉:客服回复不及时,要求升级处理。 | gpt-5.5 | {"category":"客服响应/升级处理","sentiment":"负面","suggested_action":"立即升级至客服主管或专员跟进,优先回访客户并致歉;核查未及时回复原因,给出明确处理时限和后续进展通知。","summary":"客户投诉客服回复不及时,并要求将问题升级处理。"} | {"id":"resp_4nCo3RRhzbMv9OQQUDYAux0txO9KVoa1m8i5PoE3NnD4lxzmkZs-aYH9517hYCZWNFCG1bMuT9fGxJ5gJvlSmA5Zyr-rRa_WFfDXWmzfPTpuzsdKOwXc-Or7MB3MalShXCVbY0EUE8pVxlzz6bxWwPFjZmJLKrk87C1eZxx--aNAx2giBFjmc1Ein6hhKmOX0eluXyciFF1Ug6elDowP6gGx-2PJAwzXi7AMH9k371s8yZO3tRL8FzF0a0fBmBiQQuATdWsLPslRAjHPsx1Uxj8p5XhOp3yEKDfOFrXGH8oO1wIEwxeGNVUEP68V9vCSk1VBBOOW7R29AGU0x9xNTItz0Y3AGjYYVHLve4EgkzP6u3tTM5NS7-fbP0k9IBQ0qASVxalPiSjcXbsKnYRhJFcQYn-Ph4TEGHsG9YhflNAZqXhbNFS00lXhHPoGHmrTvaF-6fTM754gGyroLSprshQdGMn-6IYQPc2_OOBf5Z-DL1wrHzTB","created_at":1781683981,"error":null,"incomplete_details":null,"instructions":"You are Codex, based on GPT-5. You are running as a coding agent in the Codex CLI on a user's computer.\n\n## General\n\n- When searching for text or files, prefer using rg or rg --files respectively because rg is much faster than alternatives like grep. (If the rg command is not found, then use alternatives.)\n\n## Editing constraints\n\n- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them.\n- Add succinct code comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare.\n- Try to use apply_patch for single file edits, but it is fine to explore other options to make the edit if it does not work well. Do not use apply_patch for changes that are auto-generated (i.e. generating package.json or running a lint or format command like gofmt) or when scripting is more efficient (such as search and replacing a string across a codebase).\n- You may be in a dirty git worktree.\n * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user.\n * If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes.\n * If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them.\n * If the changes are in unrelated files, just ignore them and don't revert them.\n- Do not amend a commit unless explicitly requested to do so.\n- While you are working, you might notice unexpected changes that you didn't make. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed.\n- NEVER use destructive commands like git reset --hard or git checkout -- unless specifically requested or approved by the user.\n\n## Plan tool\n\nWhen using the planning tool:\n- Skip using the planning tool for straightforward tasks (roughly the easiest 25%).\n- Do not make single-step plans.\n- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan.\n\n## Special user requests\n\n- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as date), you should do so.\n- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.\n\n## Presenting your work and final message\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n- Default: be very concise; friendly coding teammate tone.\n- Ask only when needed; suggest ideas; mirror the user's style.\n- For substantial work, summarize clearly; follow final‑answer formatting.\n- Skip heavy formatting for simple confirmations.\n- Don't dump large files you've written; reference paths only.\n- No "save/copy this file" - User is on the same machine.\n- Offer logical next steps (tests, commits, build) briefly; add verify steps if you couldn't do something.\n- For code changes:\n * Lead with a quick explanation of the change, and then give more details on the context covering where and why a change was made. Do not start this explanation with "summary", just jump right in.\n * If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps.\n * When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number.\n- The user does not command execution outputs. When asked to show the output of a command (e.g. git show), relay the important details in your answer or summarize the key lines so the user understands the result.\n\n### Final answer structure and style guidelines\n\n- Plain text; CLI handles styling. Use structure only when it helps scanability.\n- Headers: optional; short Title Case (1-3 words) wrapped in ...; no blank line before the first bullet; add only if they truly help.\n- Bullets: use - ; merge related points; keep to one line when possible; 4--6 per list ordered by importance; keep phrasing consistent.\n- Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **.\n- Code samples or multi-line snippets should be wrapped in fenced code blocks; include an info string as often as possible.\n- Structure: group related bullets; order sections general → specific → supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task.\n- Tone: collaborative, concise, factual; present tense, active voice; self‑contained; no "above/below"; parallel wording.\n- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short---wrap/reformat if long; avoid naming formatting styles in answers.\n- Adaptation: code explanations → precise, structured with code refs; simple tasks → lead with outcome; big changes → logical walkthrough + rationale + next actions; casual one-offs → plain sentences, no headers/bullets.\n- File References: When referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspace‑relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1‑based, optional): :line:column or #LlineCcolumn (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\repo\project\main.rs:12:5\n\n","metadata":{},"model":"gpt-5.5","object":"response","output":{"id":"msg_0dddce4567cbb853016a32571123548196a7948f16500fb6db","content":\[{"annotations":\[,"text":"{"category":"客服响应/升级处理","sentiment":"负面","suggested_action":"立即升级至客服主管或专员跟进,优先回访客户并致歉;核查未及时回复原因,给出明确处理时限和后续进展通知。","summary":"客户投诉客服回复不及时,并要求将问题升级处理。"}","type":"output_text","logprobs":\[\]}],"role":"assistant","status":"completed","type":"message","phase":"final_answer"}],"parallel_tool_calls":true,"temperature":1.0,"tool_choice":"auto","tools":\[\],"top_p":0.98,"max_output_tokens":null,"previous_response_id":null,"reasoning":{"context":"current_turn","effort":"medium","summary":"detailed"},"status":"completed","text":{"format":{"description":null,"name":"customer_ticket_analysis","schema":{"additionalProperties":false,"properties":{"category":{"type":"string"},"sentiment":{"type":"string"},"suggested_action":{"type":"string"},"summary":{"type":"string"}},"required":"sentiment","category","summary","suggested_action","type":"object"},"strict":true,"type":"json_schema"},"verbosity":"medium"},"truncation":"disabled","usage":{"input_tokens":1532,"input_tokens_details":{"audio_tokens":null,"cached_tokens":0,"text_tokens":null},"output_tokens":85,"output_tokens_details":{"reasoning_tokens":0,"text_tokens":null},"total_tokens":1617,"cost":null},"user":null,"store":false,"background":false,"completed_at":1781683986,"frequency_penalty":0,"max_tool_calls":null,"moderation":null,"presence_penalty":0,"prompt_cache_key":"34bee2673323f106","prompt_cache_retention":"24h","safety_identifier":"user-GMu5QLUX9jEXutUNMA89Gs0q","service_tier":"default","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"top_logprobs":0} |
SUCCESS | 2026-06-17 16:13:07 | 20260616 |
sql
SELECT id, source_content, model, result_text, status, error_message, processed_at
, GET_JSON_OBJECT(result_text, '$.category') AS category
, GET_JSON_OBJECT(result_text, '$.sentiment') AS sentiment
, GET_JSON_OBJECT(result_text, '$.suggested_action') AS suggested_action
, GET_JSON_OBJECT(result_text, '$.summary') AS summary
FROM bigdata_dev.tmp_dw_openai_task_result WHERE ds = '20260616'
;
| id | source_content | model | result_text | status | error_message | processed_at | category | sentiment | suggested_action | summary |
|---|---|---|---|---|---|---|---|---|---|---|
| task_001 | 客户反馈:物流太慢,包装破损,希望尽快补发。 | gpt-5.5 | {"category":"物流/包装/补发请求","sentiment":"负面","suggested_action":"立即核查物流状态和包裹破损情况,向客户致歉并优先安排补发;同时提供新的物流单号和预计送达时间,必要时给予优惠券或补偿。","summary":"客户投诉物流速度慢且收到的包装破损,要求尽快补发商品。"} | SUCCESS | 2026-06-17 16:12:48 | 物流/包装/补发请求 | 负面 | 立即核查物流状态和包裹破损情况,向客户致歉并优先安排补发;同时提供新的物流单号和预计送达时间,必要时给予优惠券或补偿。 | 客户投诉物流速度慢且收到的包装破损,要求尽快补发商品。 | |
| task_004 | 客户咨询:这个商品是否退货包运费?。 | gpt-5.5 | {"category":"退货运费政策咨询","sentiment":"中性","suggested_action":"告知客户该商品是否支持退货包运费,说明适用条件、退货流程及运费赔付方式;如需确认具体商品政策,请引导客户提供订单号或商品链接。","summary":"客户咨询该商品退货时是否包运费。"} | SUCCESS | 2026-06-17 16:46:21 | 退货运费政策咨询 | 中性 | 告知客户该商品是否支持退货包运费,说明适用条件、退货流程及运费赔付方式;如需确认具体商品政策,请引导客户提供订单号或商品链接。 | 客户咨询该商品退货时是否包运费。 | |
| task_005 | 客户反馈:这个吸尘器很好用,吸力很大,打扫干净。 | gpt-5.5 | {"category":"产品表扬","sentiment":"正面","suggested_action":"感谢客户反馈,可邀请客户进行公开评价或晒单,并推荐相关配件/耗材以提升复购。","summary":"客户对吸尘器使用体验满意,认可其吸力强、清洁效果好。"} | SUCCESS | 2026-06-17 16:46:24 | 产品表扬 | 正面 | 感谢客户反馈,可邀请客户进行公开评价或晒单,并推荐相关配件/耗材以提升复购。 | 客户对吸尘器使用体验满意,认可其吸力强、清洁效果好。 | |
| task_002 | 客户咨询:这个商品是否支持七天无理由退货? | gpt-5.5 | {"category":"退换货政策咨询","sentiment":"中性","suggested_action":"核实该商品类目和店铺退货规则,告知客户是否支持七天无理由退货;如支持,补充说明退货条件、时限、运费承担及申请路径。","summary":"客户询问该商品是否支持七天无理由退货。"} | SUCCESS | 2026-06-17 16:12:58 | 退换货政策咨询 | 中性 | 核实该商品类目和店铺退货规则,告知客户是否支持七天无理由退货;如支持,补充说明退货条件、时限、运费承担及申请路径。 | 客户询问该商品是否支持七天无理由退货。 | |
| task_003 | 客户投诉:客服回复不及时,要求升级处理。 | gpt-5.5 | {"category":"客服响应/升级处理","sentiment":"负面","suggested_action":"立即升级至客服主管或专员跟进,优先回访客户并致歉;核查未及时回复原因,给出明确处理时限和后续进展通知。","summary":"客户投诉客服回复不及时,并要求将问题升级处理。"} | SUCCESS | 2026-06-17 16:13:07 | 客服响应/升级处理 | 负面 | 立即升级至客服主管或专员跟进,优先回访客户并致歉;核查未及时回复原因,给出明确处理时限和后续进展通知。 | 客户投诉客服回复不及时,并要求将问题升级处理。 |
5. 生产化建议
- API Key 放在 DataWorks 安全参数、KMS 或环境变量中,不要明文提交。
- 大批量任务建议加限流、重试、断点续跑和失败表。
- 下游 BI 尽量只读结果表,不直接调用 API。
- 如果单日数据量大,建议按分区和批次拆分多个节点,避免单节点运行超时。
6. 其它
不需要额外引入的包
这个 demo 不需要写下面这些 import:
python
from openai import OpenAI
from odps import ODPS, DataFrame
原因:
- OpenAI API 调用使用 Python 标准库
urllib.request,不用安装openaiSDK。 - DataWorks PyODPS Python 节点通常已经提供全局 ODPS 客户端变量
o,脚本直接执行main(o)。 - 这个 demo 没有使用 PyODPS
DataFrameAPI,而是通过o.execute_sql(...)读写 MaxCompute。