From 8dc27091c65517c4f47f0476a53f634fb489a8c5 Mon Sep 17 00:00:00 2001 From: xhx1022 Date: Mon, 13 Jul 2026 21:02:17 +0800 Subject: [PATCH 1/4] support hy3 posttrain Update README files to include dataset preparation instructions and clarify key parameters for Hy3 reinforcement learning training. Enhance README files with acknowledgements for support from Tencent Hunyuan team and relevant communities. Fix typo in README by changing "Posttraining" to "Post-training" for consistency and clarity. Fix RL Post-training TOC anchor in README --- README.md | 5 + README_CN.md | 5 + assets/rl-training.png | Bin 0 -> 310636 bytes rl/README.md | 216 +++++++++++++++++++++++++++++++++++++++++ rl/README_CN.md | 216 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 442 insertions(+) create mode 100644 assets/rl-training.png create mode 100644 rl/README.md create mode 100644 rl/README_CN.md diff --git a/README.md b/README.md index 447a1415..d118cf0f 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ - [vLLM](#vllm) - [SGLang](#sglang) - [Finetuning](#finetuning) +- [RL Post-training](#rl-post-training) - [Quantization](#quantization) - [License](#license) - [Contact Us](#contact-us) @@ -205,6 +206,10 @@ python3 -m sglang.launch_server \ Hy3 provides a complete model finetuning pipeline. For detailed documentation, please refer to: [Finetuning Guide](./finetune/README.md) +## RL Post-training + +Hy3 supports GRPO reinforcement learning training with [verl](https://github.com/volcengine/verl), training on Megatron-LM (model conversion via NVIDIA Megatron-Bridge) with vLLM rollout. For detailed documentation, please refer to: [RL Training Guide](./rl/README.md) + ## Quantization We provide [AngelSlim](https://github.com/tencent/AngelSlim), a more accessible, comprehensive, and efficient toolkit for large model compression. AngelSlim supports a comprehensive suite of compression tools for large-scale multimodal models, including common quantization algorithms, low-bit quantization, and speculative sampling. diff --git a/README_CN.md b/README_CN.md index dd7b73c0..f95b1f32 100644 --- a/README_CN.md +++ b/README_CN.md @@ -41,6 +41,7 @@ - [vLLM](#使用-vllm-推理) - [SGLang](#使用-sglang-推理) - [模型微调](#模型微调) +- [强化学习训练](#强化学习训练) - [量化工具](#量化工具) - [许可证](#许可证) - [联系我们](#联系我们) @@ -205,6 +206,10 @@ python3 -m sglang.launch_server \ Hy3 提供了完整的模型微调流程,详细的微调文档请参考:[模型微调指南](./finetune/README_CN.md) +## 强化学习训练 + +Hy3 支持基于 [verl](https://github.com/volcengine/verl) 的 GRPO 强化学习训练,训练侧使用 Megatron-LM(通过 NVIDIA Megatron-Bridge 完成模型转换),rollout 侧使用 vLLM。详细文档请参考:[强化学习训练指南](./rl/README_CN.md) + ## 量化工具 我们提供了 [AngelSlim](https://github.com/tencent/AngelSlim)——一套易用、全面、高效的大模型压缩工具包,涵盖常用量化算法、低比特量化和投机采样等能力。 diff --git a/assets/rl-training.png b/assets/rl-training.png new file mode 100644 index 0000000000000000000000000000000000000000..2da8d819ee5471b11f87cf45d41ece9590abe266 GIT binary patch literal 310636 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

3VTTtOv7CuymON;8#1f@(j*C)_ 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

(%s+O_jCc_Vmmpg;RJpN-)&j&${_DjoD9tk{Y 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 U3: + +ray job submit --no-wait --runtime-env=runtime_env.yaml -- \ + bash examples/grpo_trainer/run_hy_v3_megatron.sh +``` + +> **Note**: on H20, rollout (vLLM inference) requires at least TP=16 (the script defaults to `ROLLOUT_TP=16`) — the weights of a single instance only fit when sharded across 16 GPUs. + +### Key parameters + +**Hy3 settings** + +| Parameter | Value | Reason | +| --- | --- | --- | +| `moe_router_enable_expert_bias` | True | Hy3 routes with a per-expert bias (aux-loss-free) | +| `moe_router_bias_update_rate` | 0 | 0 freezes the bias (it still participates in scoring but is never updated) | +| `moe_router_load_balancing_type` | none | no auxiliary load-balancing loss | + +**Training setup** + +| Parameter | What it does | +| --- | --- | +| `data.train_batch_size` | prompts sampled per step | +| `rollout.n` | responses generated per prompt, i.e. the GRPO group size (the in-group advantage baseline is computed over them), typically 8–16 | +| `actor.ppo_mini_batch_size` | samples per actor parameter update | +| `actor.optim.lr` | actor learning rate, typically the 1e-6 scale | +| `data.max_response_length` | maximum generation length, task-dependent | + +**Algorithm behavior** + +| Parameter | What it does | How to set it | +| --- | --- | --- | +| `algorithm.norm_adv_by_std_in_grpo` | whether advantages are divided by the in-group std | True is original GRPO; False is the [Dr.GRPO](https://arxiv.org/abs/2503.20783) fix, preventing too-easy/too-hard prompts with tiny variance from being amplified | +| `actor.clip_ratio_low` / `clip_ratio_high` | PPO trust-region bounds | a slightly relaxed upper bound (clip-higher, e.g. 0.2/0.28) gives low-probability tokens more room to rise, mitigating entropy collapse | +| `actor.clip_ratio_c` | [dual-clip](https://arxiv.org/abs/1912.09729) lower-bound constant | caps the penalty on negative-advantage tokens to keep a single step from blowing up the policy | +| `actor.kl_loss_coef` | KL-regularization strength toward the reference policy | 0 means KL-free (rely on clipping); add a small value (e.g. 1e-3) if training is unstable | +| `algorithm.rollout_correction.rollout_is` / `rollout_is_threshold` | correction for the rollout/training log-prob mismatch (IcePop) | `token` plus lower/upper bounds (e.g. `0.5_4.0`; token weights outside the range are zeroed); recommended whenever the numeric gap between the two engines is non-negligible | +| `rollout.temperature` / `top_p` | rollout sampling exploration strength | typically 0.9–1.0; too low a temperature reduces in-group diversity and degrades the GRPO baseline | + +**Memory and sequence length** + +Parameters that must move together when extending the sequence length (changing `data.max_response_length` alone is not enough): + +| Parameter | Coupling | +| --- | --- | +| `data.max_response_length` | target response length | +| `rollout.max_model_len` | vLLM context length, must be ≥ prompt + response | +| `actor.ppo_max_token_len_per_gpu` | training-side per-GPU token budget; sequences are split across CP ranks, so each GPU actually holds `(prompt+response)/CP` per sequence — the requirement is budget × CP ≥ prompt + response | +| `actor.megatron.context_parallel_size` | scale up proportionally for much longer sequences (activation memory grows linearly with sequence length and is sharded by CP) | + +For training-side OOM (the error occurs during actor update / log_prob), you can try: + +1. Lower `actor.ppo_max_token_len_per_gpu` — dynamic batching packs micro batches against it, so it directly bounds the activation peak; +2. Set `actor.ppo_micro_batch_size_per_gpu` to 1; +3. Lower `ref.log_prob_max_token_len_per_gpu` / `rollout.log_prob_max_token_len_per_gpu`; +4. Raise `actor.megatron.context_parallel_size` (activations are sharded by CP) or `pipeline_model_parallel_size` (fewer layers per stage). + +Offload and recompute: + +| Config | Script default | What it does | +| --- | --- | --- | +| `actor.megatron.param_offload` | True | offloads parameters to CPU while training is idle, freeing GPU memory for rollout | +| `actor.megatron.optimizer_offload` | True | offloads optimizer state (fp32 master weights + momenta — the biggest memory consumer) to CPU | +| `actor.megatron.grad_offload` | True | offloads gradient buffers to CPU | +| `override_transformer_config.recompute_granularity` | full | full activation recomputation: forward stores no activations, backward recomputes them — trades ~30% extra compute for most of the activation memory | +| `override_transformer_config.recompute_method` / `recompute_num_layers` | uniform / 1 | recompute uniformly at 1-layer granularity — the finest granularity, lowest peak | + +Both substantially relieve OOM: offload keeps parameters/optimizer state/gradients out of GPU memory at the cost of per-step CPU↔GPU transfers, and recompute keeps activations out of GPU memory at the cost of one extra forward pass during backward. + +## Customizing Your Training + +### Using your own dataset + +verl reads parquet data where each row contains 5 fields (see the verl docs: [Prepare Data](https://verl.readthedocs.io/en/latest/preparation/prepare_data.html)): + +```python +{ + "data_source": "my_dataset", # dataset name; the RewardManager uses it to index the scoring function + "prompt": [ # HuggingFace chat template format; the tokenizer renders and tokenizes it + {"role": "user", "content": "1+1=?"} + ], + "ability": "math", # task category + "reward_model": { + "style": "rule", + "ground_truth": "2" # reference answer; the reward function's scoring logic must align with its format + }, + "extra_info": {"split": "train", "index": 0}, # metadata +} +``` + +Write a preprocessing script that converts your data into this format (verl's [`examples/data_preprocess/`](https://github.com/verl-project/verl/tree/main/examples/data_preprocess) ships a dozen ready-to-adapt templates — GSM8K, MATH, etc.), save as parquet, then point the script at your files via environment variables: + +```bash +TRAIN_FILES=/path/to/my_train.parquet \ +VAL_FILES=/path/to/my_val.parquet \ +bash examples/grpo_trainer/run_hy_v3_megatron.sh +``` + +**Reward function**: math-style tasks with rule-verifiable answers can reuse the default DAPO reward as-is (it routes to a built-in scoring function by `data_source`); other tasks need a custom reward function, specified via `custom_reward_function.path` (see the verl docs: [Implement Reward Function](https://verl.readthedocs.io/en/latest/preparation/reward_function.html)). + +### Switching the RL algorithm + +The script defaults to GRPO, but the algorithm layer is decoupled from the model layer, so switching algorithms requires no changes to the Hy3-specific configuration. + +**Switch between built-in algorithms (one config key)**: verl ships a dozen advantage estimators, selected via `algorithm.adv_estimator` — options include `gae` (PPO), `grpo`, `rloo`, `remax`, `reinforce_plus_plus`, `opo`, `gpg`, etc. (full list in `AdvantageEstimator` in [`core_algos.py`](https://github.com/verl-project/verl/blob/main/verl/trainer/ppo/core_algos.py)); the policy loss is selected via `actor_rollout_ref.actor.policy_loss.loss_mode` (`vanilla`, `gspo`, `cispo`, `clip_cov`, etc.). See the verl docs for each algorithm's theory and configuration: [PPO](https://verl.readthedocs.io/en/latest/algo/ppo.html) / [GRPO](https://verl.readthedocs.io/en/latest/algo/grpo.html) / [DAPO](https://verl.readthedocs.io/en/latest/algo/dapo.html). + +**Training Hy3 with a recipe**: full-pipeline algorithms (e.g. DAPO with dynamic sampling) live as standalone implementations under verl's [`recipe/`](https://github.com/verl-project/verl/tree/main/recipe) directory, each with its own launch script. When pointing a recipe at Hy3, carry over the following required Hy3 settings into the recipe's launch script: + +```bash +# Required Hy3 settings (apply to any recipe) +actor_rollout_ref.model.path=/path/to/Hy3 +actor_rollout_ref.model.trust_remote_code=True +data.trust_remote_code=True +actor_rollout_ref.actor.megatron.use_mbridge=True +actor_rollout_ref.actor.megatron.vanilla_mbridge=False ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_router_enable_expert_bias=True ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_router_bias_update_rate=0 ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_router_load_balancing_type=none ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_grouped_gemm=True +``` + +For implementing entirely new algorithms, see the verl docs: [Extend to other RL algorithms](https://verl.readthedocs.io/en/latest/advance/dpo_extension.html). + +## Results + +We launched Hy3 GRPO training on 128 H20 GPUs (16 nodes × 8) with [`run_hy_v3_megatron.sh`](https://github.com/verl-project/verl/blob/main/examples/grpo_trainer/run_hy_v3_megatron.sh): math reasoning on the DAPO dataset at 8192 max response length, with PP/CP/EP parallelism plus full offload, and BF16 rollout + BF16 training. + +Exact values used in this run: batch 128 prompts × 16 samples (2048 trajectories/step), `ppo_mini_batch_size=128` (one update per step), lr 1e-6, clip 0.2/0.28 (dual-clip c=10.0), KL-free, DAPO overlong buffer (len 4096 / penalty 1.0), IcePop threshold `0.5_4.0`, sampling temperature 0.9 / top_p 1.0. + +The training dynamics are stable: the rollout/training log-prob drift (`rollout_probs_diff`) stays below 0.015 throughout, and both reward and the AIME validation score grow steadily over the run. + +![Hy3 RL training curves](../assets/rl-training.png) + +## Acknowledgements + +We thank the Tencent Hunyuan team for their support on model training and engineering, as well as the [verl](https://github.com/volcengine/verl), [Megatron-Bridge](https://github.com/NVIDIA-NeMo/Megatron-Bridge), [Megatron-LM](https://github.com/NVIDIA/Megatron-LM), and [vLLM](https://github.com/vllm-project/vllm) communities for their help. diff --git a/rl/README_CN.md b/rl/README_CN.md new file mode 100644 index 00000000..45e104e5 --- /dev/null +++ b/rl/README_CN.md @@ -0,0 +1,216 @@ +# Hy3 强化学习训练 + +[English](./README.md) | 简体中文 + +本文档介绍如何使用 [verl](https://github.com/volcengine/verl) 对 Hy3 进行强化学习训练。训练侧使用 [Megatron-LM](https://github.com/NVIDIA/Megatron-LM),并通过 NVIDIA [Megatron-Bridge](https://github.com/NVIDIA-NeMo/Megatron-Bridge)(`HYV3Bridge`)在训练启动时将 HF checkpoint 在线转换为 Megatron 模型,无需离线转换;rollout 侧使用 [vLLM](https://github.com/vllm-project/vllm)。 + +训练脚本:verl 仓库 [`examples/grpo_trainer/run_hy_v3_megatron.sh`](https://github.com/verl-project/verl/blob/main/examples/grpo_trainer/run_hy_v3_megatron.sh) + +## 快速开始 + +### 环境 + +推荐镜像:`verlai/verl:vllm023.dev1` + +已验证的版本组合: + +| 组件 | 版本 | +| --- | --- | +| verl | [220e903](https://github.com/verl-project/verl/commit/220e9039902c6db56860e2afd659803dc34ec005) | +| Megatron-Bridge | [df0852c](https://github.com/NVIDIA-NeMo/Megatron-Bridge/commit/df0852cf94c674de07f9f7ef933c484de8aca505) | +| transformers | 5.6.0 | +| nvidia-modelopt | 0.44.0rc5 | + +### 准备依赖 + +clone verl 并切换到已验证版本,然后在仓库根目录下将依赖 clone 到 `third_party/`: + +```bash +git clone https://github.com/verl-project/verl.git +cd verl +git checkout 220e903 + +mkdir third_party +git clone https://github.com/NVIDIA-NeMo/Megatron-Bridge.git third_party/Megatron-Bridge +git -C third_party/Megatron-Bridge checkout df0852c + +git clone https://github.com/Ascend/TransferQueue.git third_party/TransferQueue +``` + +编写 `runtime_env.yaml`,通过 Ray runtime env 将工作目录(含 `third_party/`)分发到各 worker 节点,并加入 `PYTHONPATH`: + +```yaml +# runtime_env.yaml +working_dir: ./ +excludes: [ + "/.git/", + "/third_party/Megatron-Bridge/.git/", + "/third_party/TransferQueue/.git/", + "**/__pycache__/", +] +env_vars: + PYTHONPATH: third_party/Megatron-Bridge/src:third_party/TransferQueue +``` + +### 准备数据集 + +脚本默认使用 [DAPO-Math-17k](https://huggingface.co/datasets/BytedTsinghua-SIA/DAPO-Math-17k)(训练)和 [AIME-2024](https://huggingface.co/datasets/BytedTsinghua-SIA/AIME-2024)(验证),两者在 HuggingFace 上已是 verl 所需格式,下载后转存 parquet 即可: + +```python +# prepare_data.py +import datasets + +dapo = datasets.load_dataset("BytedTsinghua-SIA/DAPO-Math-17k", "default")["train"] +dapo.to_parquet("DAPO-Math-17k/dapo-math-17k.parquet") + +aime = datasets.load_dataset("BytedTsinghua-SIA/AIME-2024", "default")["train"] +aime.to_parquet("AIME-2024/aime-2024.parquet") +``` + +```bash +python prepare_data.py # 输出路径与脚本默认的 DATA_DIR 布局一致 +``` + +数据放在 verl 仓库根目录(`DATA_DIR` 默认为 `$PWD`)下,或通过 `DATA_DIR=/path/to/data` 指定。 + +### 提交任务 + +模型直接使用 HuggingFace 格式 checkpoint,训练数据为 parquet 格式。设置 `RAY_ADDRESS` 指向集群 head 节点后,通过 `ray job submit` 提交: + +```bash +export RAY_ADDRESS=http://: + +ray job submit --no-wait --runtime-env=runtime_env.yaml -- \ + bash examples/grpo_trainer/run_hy_v3_megatron.sh +``` + +> **注**:H20 上 rollout(vLLM 推理)最小需要 TP=16(脚本默认 `ROLLOUT_TP=16`),单实例权重需跨 16 卡切分才放得下。 + +### 关键参数 + +**Hy3配置** + +| 参数 | 值 | 原因 | +| --- | --- | --- | +| `moe_router_enable_expert_bias` | True | Hy3 使用 per-expert bias 路由(aux-loss-free) | +| `moe_router_bias_update_rate` | 0 | 设 0 冻结 bias(只参与打分、不再更新)。 | +| `moe_router_load_balancing_type` | none | 不使用辅助负载均衡 loss | + +**训练设置** + +| 参数 | 作用 | +| --- | --- | +| `data.train_batch_size` | 每步采样的 prompt 数 | +| `rollout.n` | 每个 prompt 生成的 response 数,即 GRPO 组大小(组内计算 advantage 基线),常用 8–16; +| `actor.ppo_mini_batch_size` | actor 每次参数更新的样本量 | +| `actor.optim.lr` | actor 学习率,常用 1e-6 量级 | +| `data.max_response_length` | 最长生成长度,依任务而定 | + +**算法行为** + +| 参数 | 作用 | 怎么设 | +| --- | --- | --- | +| `algorithm.norm_adv_by_std_in_grpo` | advantage 是否除以组内 std | True 为原版 GRPO;False 为 [Dr.GRPO](https://arxiv.org/abs/2503.20783) 修正,避免过易/过难样本因方差小被放大 | +| `actor.clip_ratio_low` / `clip_ratio_high` | PPO 信任域上下界 | 上界略放宽(clip-higher,如 0.2/0.28)给低概率 token 更多上升空间,缓解熵坍缩 | +| `actor.clip_ratio_c` | [dual-clip](https://arxiv.org/abs/1912.09729) 下界常数 | 封顶负 advantage token 的惩罚,防止策略被单步拉爆 | +| `actor.kl_loss_coef` | 向参考策略的 KL 正则强度 | 0 为 KL-free(靠 clip 约束);训练不稳时可加小值(如 1e-3) | +| `algorithm.rollout_correction.rollout_is` / `rollout_is_threshold` | rollout 与训练引擎的 log-prob 偏差校正(IcePop) | `token` + 上下阈值(如 `0.5_4.0`,权重超界的 token 置零);两侧引擎精度偏差不可忽略时建议开启 | +| `rollout.temperature` / `top_p` | rollout 采样探索强度 | 常用 0.9–1.0;温度过低组内多样性不足,GRPO 组内基线退化 | + +**显存与序列长度** + +| 参数 | 联动关系 | +| --- | --- | +| `data.max_response_length` | 目标响应长度 | +| `rollout.max_model_len` | vLLM 上下文长度,需 ≥ prompt + response | +| `actor.ppo_max_token_len_per_gpu` | 训练侧每卡 token 预算;序列被 CP 切分到多卡,单条序列每卡实际占 `(prompt+response)/CP`,故需满足 预算 × CP ≥ prompt + response | +| `actor.megatron.context_parallel_size` | 序列显著变长时按比例增大(激活显存随序列长度线性增长,由 CP 分摊) | + +训练侧 OOM(报错发生在 actor update / log_prob 阶段),可尝试: + +1. 调小 `actor.ppo_max_token_len_per_gpu`——动态 batch 按它打包 micro batch,直接决定激活峰值; +2. `actor.ppo_micro_batch_size_per_gpu` 调为 1; +3. 调小 `ref.log_prob_max_token_len_per_gpu` / `rollout.log_prob_max_token_len_per_gpu`; +4. 增大 `actor.megatron.context_parallel_size`(激活按 CP 分摊)或 `pipeline_model_parallel_size`(每 stage 层数更少)。 + +offload 与 recompute: + +| 配置 | 脚本默认 | 作用 | +| --- | --- | --- | +| `actor.megatron.param_offload` | True | 训练空闲期把参数下放 CPU,给 rollout 腾显存 | +| `actor.megatron.optimizer_offload` | True | 优化器状态(fp32 master 权重 + 动量,显存大头)放 CPU | +| `actor.megatron.grad_offload` | True | 梯度缓冲放 CPU | +| `override_transformer_config.recompute_granularity` | full | 全量激活重算:前向不存激活、反向重算,用约 30% 额外计算换掉大部分激活显存 | +| `override_transformer_config.recompute_method` / `recompute_num_layers` | uniform / 1 | 按每 1 层为单位均匀重算,粒度最细、峰值最低 | + +两者都能显著缓解 OOM,offload 用每步 CPU↔GPU 搬运耗时换取参数/优化器/梯度不占显存,recompute 用反向多一次前向计算换取激活不占显存。 + +## 自定义训练 + +### 使用自己的数据集 + +verl 读取 parquet 格式数据,每行需包含 5 个字段(详见 verl 官方文档 [Prepare Data](https://verl.readthedocs.io/en/latest/preparation/prepare_data.html)): + +```python +{ + "data_source": "my_dataset", # 数据集名称,RewardManager 据此索引对应的打分函数 + "prompt": [ # HuggingFace chat template 格式,tokenizer 会渲染并分词 + {"role": "user", "content": "1+1=?"} + ], + "ability": "math", # 任务类别 + "reward_model": { + "style": "rule", + "ground_truth": "2" # 标准答案;reward 函数的判分逻辑须与其格式对齐 + }, + "extra_info": {"split": "train", "index": 0}, # 元信息 +} +``` + +编写预处理脚本转换为上述格式(verl 的 [`examples/data_preprocess/`](https://github.com/verl-project/verl/tree/main/examples/data_preprocess) 提供了 GSM8K、MATH 等十余个可直接套用的模板),保存为 parquet 后通过环境变量指定: + +```bash +TRAIN_FILES=/path/to/my_train.parquet \ +VAL_FILES=/path/to/my_val.parquet \ +bash examples/grpo_trainer/run_hy_v3_megatron.sh +``` + +**reward 函数**:答案可规则判分的数学类任务可直接沿用默认的 DAPO reward(按 `data_source` 自动路由到内置打分函数);其他任务需自定义 reward 函数,通过 `custom_reward_function.path` 指定(见 verl 文档 [Implement Reward Function](https://verl.readthedocs.io/en/latest/preparation/reward_function.html))。 + + +### 更换 RL 算法 + +训练脚本默认 GRPO,但算法层与模型层解耦,换算法时 Hy3 相关配置无需改动。 + +**切换内置算法(改一个配置项)**:verl 内置了十余种 advantage 估计器,通过 `algorithm.adv_estimator` 直接切换,可选值包括 `gae`(PPO)、`grpo`、`rloo`、`remax`、`reinforce_plus_plus`、`opo`、`gpg` 等(完整列表见 [`core_algos.py`](https://github.com/verl-project/verl/blob/main/verl/trainer/ppo/core_algos.py) 的 `AdvantageEstimator`);policy loss 通过 `actor_rollout_ref.actor.policy_loss.loss_mode` 切换(`vanilla`、`gspo`、`cispo`、`clip_cov` 等)。各算法的原理与配置说明见 verl 文档:[PPO](https://verl.readthedocs.io/en/latest/algo/ppo.html) / [GRPO](https://verl.readthedocs.io/en/latest/algo/grpo.html) / [DAPO](https://verl.readthedocs.io/en/latest/algo/dapo.html)。 + + +**使用 recipe 训练 Hy3**:训练流程级的完整算法(如 dynamic sampling 版 DAPO)在 verl [`recipe/`](https://github.com/verl-project/verl/tree/main/recipe) 目录下有独立实现,各自带启动脚本。将其模型指向 Hy3 时,须把以下 Hy3 必需配置带入 recipe 的启动脚本: + +```bash +# Hy3 必需配置(任何 recipe 通用) +actor_rollout_ref.model.path=/path/to/Hy3 +actor_rollout_ref.model.trust_remote_code=True +data.trust_remote_code=True +actor_rollout_ref.actor.megatron.use_mbridge=True +actor_rollout_ref.actor.megatron.vanilla_mbridge=False ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_router_enable_expert_bias=True ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_router_bias_update_rate=0 ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_router_load_balancing_type=none ++actor_rollout_ref.actor.megatron.override_transformer_config.moe_grouped_gemm=True +``` + +自定义全新算法的扩展方式见 verl 文档 [Extend to other RL algorithms](https://verl.readthedocs.io/en/latest/advance/dpo_extension.html)。 + +## 实验结果 + +我们在 128 张 H20 GPU(16 机 × 8 卡)上启动了 Hy3 的 GRPO 训练(脚本:[`run_hy_v3_megatron.sh`](https://github.com/verl-project/verl/blob/main/examples/grpo_trainer/run_hy_v3_megatron.sh)):数学推理任务(DAPO 数据集),max response length 8192,采用 PP/CP/EP 多维并行 + 全量 offload,BF16 rollout + BF16 训练。 + +本次实验的具体取值:batch 128 prompts × 16 samples(2048 条轨迹/步)、`ppo_mini_batch_size=128`(每步单次更新)、lr 1e-6、clip 0.2/0.28(dual-clip c=10.0)、KL-free、DAPO overlong buffer(len 4096 / penalty 1.0)、IcePop 阈值 `0.5_4.0`、采样 temperature 0.9 / top_p 1.0。 + +训练动态稳定:rollout 与训练侧的 log-prob 偏差(`rollout_probs_diff`)全程基本小于 0.015,reward 与 AIME 验证集分数在整个训练过程中稳步上升。 + +![Hy3 RL 训练曲线](../assets/rl-training.png) + +## 致谢 + +感谢腾讯混元(Hunyuan)团队在模型训练与工程落地上的支持,以及 [verl](https://github.com/volcengine/verl)、[Megatron-Bridge](https://github.com/NVIDIA-NeMo/Megatron-Bridge)、[Megatron-LM](https://github.com/NVIDIA/Megatron-LM)、[vLLM](https://github.com/vllm-project/vllm) 社区的帮助。 From 441607155def3229bead412db9340d01191b1ca9 Mon Sep 17 00:00:00 2001 From: Hongxin Xu <70438206+xhx1022@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:32:29 +0800 Subject: [PATCH 2/4] Update README.md --- rl/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rl/README.md b/rl/README.md index 91c200b5..b07fe3da 100644 --- a/rl/README.md +++ b/rl/README.md @@ -213,4 +213,4 @@ The training dynamics are stable: the rollout/training log-prob drift (`rollout_ ## Acknowledgements -We thank the Tencent Hunyuan team for their support on model training and engineering, as well as the [verl](https://github.com/volcengine/verl), [Megatron-Bridge](https://github.com/NVIDIA-NeMo/Megatron-Bridge), [Megatron-LM](https://github.com/NVIDIA/Megatron-LM), and [vLLM](https://github.com/vllm-project/vllm) communities for their help. +We thank the Tencent Hunyuan team for their support on model training and engineering infrastructure, as well as the [verl](https://github.com/volcengine/verl), [Megatron-Bridge](https://github.com/NVIDIA-NeMo/Megatron-Bridge), [Megatron-LM](https://github.com/NVIDIA/Megatron-LM), and [vLLM](https://github.com/vllm-project/vllm) communities for their help. From c82469cae54fb4a4026e8fba6f4c8512db744885 Mon Sep 17 00:00:00 2001 From: wmz <1815960674@qq.com> Date: Thu, 16 Jul 2026 23:50:03 +0800 Subject: [PATCH 3/4] feat: add Hy3 API quickstart and examples for issue #1 - quickstart.md: API basics, curl/Python examples, parameter guide, troubleshooting - 6 runnable examples under issue1/examples/: basic_chat, streaming, latency_compare, tool_calling, reasoning_mode, retry - each example includes .py (runnable) and .md (documentation) - uses TokenHub OpenAI-compatible API (hy3-preview) - .gitignore updated to exclude .env files - api_demo.py: standalone API demo under project root --- .env.example | 11 ++ .gitignore | 1 + api_demo.py | 111 +++++++++++++ issue1/.env.example | 14 ++ issue1/examples/basic_chat.md | 96 +++++++++++ issue1/examples/basic_chat.py | 100 ++++++++++++ issue1/examples/latency_compare.md | 112 +++++++++++++ issue1/examples/latency_compare.py | 140 ++++++++++++++++ issue1/examples/reasoning_mode.md | 113 +++++++++++++ issue1/examples/reasoning_mode.py | 128 +++++++++++++++ issue1/examples/retry.md | 157 ++++++++++++++++++ issue1/examples/retry.py | 211 ++++++++++++++++++++++++ issue1/examples/streaming.md | 121 ++++++++++++++ issue1/examples/streaming.py | 98 ++++++++++++ issue1/examples/tool_calling.md | 155 ++++++++++++++++++ issue1/examples/tool_calling.py | 161 +++++++++++++++++++ issue1/quickstart.md | 247 +++++++++++++++++++++++++++++ requirements.txt | 2 + 18 files changed, 1978 insertions(+) create mode 100644 .env.example create mode 100644 api_demo.py create mode 100644 issue1/.env.example create mode 100644 issue1/examples/basic_chat.md create mode 100644 issue1/examples/basic_chat.py create mode 100644 issue1/examples/latency_compare.md create mode 100644 issue1/examples/latency_compare.py create mode 100644 issue1/examples/reasoning_mode.md create mode 100644 issue1/examples/reasoning_mode.py create mode 100644 issue1/examples/retry.md create mode 100644 issue1/examples/retry.py create mode 100644 issue1/examples/streaming.md create mode 100644 issue1/examples/streaming.py create mode 100644 issue1/examples/tool_calling.md create mode 100644 issue1/examples/tool_calling.py create mode 100644 issue1/quickstart.md create mode 100644 requirements.txt diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..703a7a5a --- /dev/null +++ b/.env.example @@ -0,0 +1,11 @@ +# 腾讯混元 Hy3 API 配置 +# 复制此文件为 .env 并填入你的 API Key + +# TokenHub API Key(获取地址:https://console.cloud.tencent.com/tokenhub/apikey) +HY3_API_KEY=your_api_key_here + +# TokenHub Base URL(OpenAI 兼容接口) +HY3_BASE_URL=https://tokenhub.tencentmaas.com/v1 + +# 模型名称: hy3-preview(推荐,256K上下文)或 hy3 +HY3_MODEL=hy3-preview diff --git a/.gitignore b/.gitignore index 56137961..380b3abc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ Thumbs.db __pycache__/ *.pyc +.env diff --git a/api_demo.py b/api_demo.py new file mode 100644 index 00000000..234c671c --- /dev/null +++ b/api_demo.py @@ -0,0 +1,111 @@ +""" +腾讯混元 Hy3 API 调用示例 +使用 OpenAI 兼容接口,支持普通对话、深度推理、Function Calling 等模式。 +""" +import os +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv() + +client = OpenAI( + api_key=os.getenv("HY3_API_KEY"), + base_url=os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1"), +) + +MODEL = os.getenv("HY3_MODEL", "hy3-preview") + + +def chat(prompt: str, reasoning_effort: str = "no_think") -> str: + """ + 普通对话 / 深度推理 + + Args: + prompt: 用户输入 + reasoning_effort: "no_think" (直接回复), "low", "high" (深度思维链) + """ + response = client.chat.completions.create( + model=MODEL, + messages=[{"role": "user", "content": prompt}], + temperature=0.9, + top_p=1.0, + extra_body={"chat_template_kwargs": {"reasoning_effort": reasoning_effort}}, + ) + return response.choices[0].message.content + + +def chat_stream(prompt: str, reasoning_effort: str = "no_think"): + """流式对话(逐字输出)""" + stream = client.chat.completions.create( + model=MODEL, + messages=[{"role": "user", "content": prompt}], + temperature=0.9, + top_p=1.0, + stream=True, + extra_body={"chat_template_kwargs": {"reasoning_effort": reasoning_effort}}, + ) + for chunk in stream: + if chunk.choices[0].delta.content: + print(chunk.choices[0].delta.content, end="", flush=True) + print() + + +def chat_with_tools(prompt: str, tools: list[dict]) -> dict: + """带 Function Calling 的对话""" + messages = [{"role": "user", "content": prompt}] + response = client.chat.completions.create( + model=MODEL, + messages=messages, + tools=tools, + temperature=0.9, + top_p=1.0, + ) + return response.choices[0].message + + +# ─── 使用示例 ───────────────────────────────────────────── + +if __name__ == "__main__": + # 1. 普通对话(无推理) + print("=" * 60) + print("【普通对话】") + print("=" * 60) + result = chat("你好!请用一句话介绍你自己。") + print(result) + print() + + # 2. 深度推理(复杂任务) + print("=" * 60) + print("【深度推理 - 数学题】") + print("=" * 60) + result = chat( + "设 f(x) = x³ - 6x² + 11x - 6,求 f(x) 在区间 [0, 4] 上的最大值和最小值。", + reasoning_effort="high", + ) + print(result) + print() + + # 3. Function Calling 示例 + print("=" * 60) + print("【Function Calling - 获取天气】") + print("=" * 60) + tools = [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "获取指定城市的天气信息", + "parameters": { + "type": "object", + "properties": { + "city": {"type": "string", "description": "城市名称"}, + }, + "required": ["city"], + }, + }, + } + ] + msg = chat_with_tools("北京今天天气怎么样?", tools) + print(f"tool_calls: {msg.tool_calls}") + print() + print("所有示例运行完成!") diff --git a/issue1/.env.example b/issue1/.env.example new file mode 100644 index 00000000..91c3adc0 --- /dev/null +++ b/issue1/.env.example @@ -0,0 +1,14 @@ +# Hy3 API Quickstart 配置 +# 复制此文件为 .env 并填入你的 API Key +# +# 获取 API Key: https://console.cloud.tencent.com/tokenhub/apikey +# 新用户可领取 100 万 Tokens 免费额度(90 天有效) + +# TokenHub API Key(必填) +HY3_API_KEY=your_api_key_here + +# TokenHub Base URL(OpenAI 兼容接口) +HY3_BASE_URL=https://tokenhub.tencentmaas.com/v1 + +# 模型名称: hy3-preview(推荐,256K 上下文)或 hy3 +HY3_MODEL=hy3-preview diff --git a/issue1/examples/basic_chat.md b/issue1/examples/basic_chat.md new file mode 100644 index 00000000..fad44fb9 --- /dev/null +++ b/issue1/examples/basic_chat.md @@ -0,0 +1,96 @@ +# Basic Chat — 单轮与多轮对话 + +演示 Hy3 API 的基础对话能力,包含单轮问答和多轮上下文对话。多轮对话通过将历史的 assistant 回复加入 `messages` 列表来实现上下文传递。 + +## 运行 + +```bash +cd issue1 +python examples/basic_chat.py +``` + +## 请求结构 + +### 单轮对话 + +```python +{ + "model": "hy3-preview", + "messages": [ + {"role": "user", "content": "请用一句话介绍腾讯混元 Hy3 模型。"} + ], + "temperature": 0.9, + "top_p": 1.0, + "max_tokens": 128 +} +``` + +### 多轮对话 + +多轮对话的核心在于保留 `messages` 中的历史对话,让模型能够理解上下文: + +```python +{ + "model": "hy3-preview", + "messages": [ + {"role": "user", "content": "请用一句话介绍腾讯混元 Hy3 模型。"}, + {"role": "assistant", "content": "Hy3 是腾讯混元团队研发的..."}, + {"role": "user", "content": "那么它在代码生成方面有什么优势?请列出 3 点。"} + ], + "temperature": 0.7, + "top_p": 1.0, + "max_tokens": 256 +} +``` + +> **关键设计**:OpenAI Chat Completions API 是无状态的。每次请求都必须携带完整的对话历史,模型不会「记住」之前的任何交互。 + +## 响应解析 + +```python +response = client.chat.completions.create(**params) +choice = response.choices[0] + +# 关键字段提取 +message_id = response.id # 本次请求的唯一 ID +model_name = response.model # 实际使用的模型名 +finish_reason = choice.finish_reason # stop / length / content_filter +content = choice.message.content # 模型回复正文 +token_usage = response.usage # {prompt_tokens, completion_tokens, total_tokens} +``` + +### finish_reason 含义 + +| 值 | 含义 | +|:---|:---| +| `stop` | 正常结束,模型自然完成或命中 stop 序列 | +| `length` | 达到 max_tokens 上限被截断 | +| `content_filter` | 内容被安全过滤 | + +## 示例输出 + +以下为实际调用 TokenHub `hy3-preview` 的输出: + +``` +=== 单轮对话 === +模型: hy3-preview +完成原因: stop +回复: 腾讯混元 Hy3 是腾讯自研的 295B 参数混合专家大模型,以 21B 激活参数实现高效推理,在代码、数学、长文本等任务上表现优异。 +Token 用量: {'prompt_tokens': 12, 'completion_tokens': 41, 'total_tokens': 53} + +=== 多轮对话 === +模型: hy3-preview +完成原因: stop +回复: Hy3 在代码生成方面具有以下优势: + +1. **多语言覆盖**:支持 Python、Java、C++、Go、TypeScript 等主流语言,代码风格规范统一。 +2. **上下文理解**:256K 的长上下文窗口使其能理解整个项目结构,生成与现有代码库风格一致的代码。 +3. **推理驱动生成**:在复杂算法和架构设计任务中,可通过深度思考模式先分析再编码,减少逻辑错误。 +Token 用量: {'prompt_tokens': 65, 'completion_tokens': 116, 'total_tokens': 181} +``` + +## 关键要点 + +1. **温度参数**:单轮开放对话推荐 `0.9`,多轮收紧至 `0.7` 以保持回答一致性 +2. **Token 计数**:多轮对话的 `prompt_tokens` 随历史增长,需注意上下文预算 +3. **历史管理**:生产环境中应实现滑动窗口或摘要机制,避免 messages 过长 diff --git a/issue1/examples/basic_chat.py b/issue1/examples/basic_chat.py new file mode 100644 index 00000000..23a8c2fb --- /dev/null +++ b/issue1/examples/basic_chat.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +""" +Hy3 基础对话示例:单轮对话与多轮对话。 + +使用方式: + cd issue1 + python examples/basic_chat.py + +前置条件: + 1. 复制 .env.example 为 .env 并填入 HY3_API_KEY + 2. pip install "openai>=1.0.0" python-dotenv +""" + +import os +import sys +from pathlib import Path + +# 将 issue1 目录加入路径,以便加载根目录的 .env +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv(Path(__file__).resolve().parents[1] / ".env") + +# ── 配置 ───────────────────────────────────────────── +BASE_URL = os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1") +API_KEY = os.getenv("HY3_API_KEY", "") +MODEL = os.getenv("HY3_MODEL", "hy3-preview") + +client = OpenAI(base_url=BASE_URL, api_key=API_KEY) + + +def chat(messages: list[dict], **kwargs) -> dict: + """发送请求并返回解析后的关键字段。""" + params = { + "model": MODEL, + "messages": messages, + "temperature": kwargs.get("temperature", 0.9), + "top_p": kwargs.get("top_p", 1.0), + "max_tokens": kwargs.get("max_tokens", 256), + } + response = client.chat.completions.create(**params) + choice = response.choices[0] + return { + "id": response.id, + "model": response.model, + "finish_reason": choice.finish_reason, + "content": choice.message.content, + "usage": { + "prompt_tokens": response.usage.prompt_tokens if response.usage else 0, + "completion_tokens": response.usage.completion_tokens if response.usage else 0, + "total_tokens": response.usage.total_tokens if response.usage else 0, + }, + } + + +def main(): + print("=" * 60) + print("【示例 1】单轮对话") + print("=" * 60) + + single_messages = [ + {"role": "user", "content": "请用一句话介绍腾讯混元 Hy3 模型。"} + ] + print(f"\n请求 messages:\n{single_messages}\n") + + result = chat(single_messages, temperature=0.9, max_tokens=128) + print(f"模型: {result['model']}") + print(f"完成原因: {result['finish_reason']}") + print(f"回复: {result['content']}") + print(f"Token 用量: {result['usage']}") + + # ── 多轮对话 ───────────────────────────────────── + print("\n" + "=" * 60) + print("【示例 2】多轮对话") + print("=" * 60) + + multi_messages = [ + {"role": "user", "content": "请用一句话介绍腾讯混元 Hy3 模型。"}, + {"role": "assistant", "content": result["content"]}, + { + "role": "user", + "content": "那么它在代码生成方面有什么优势?请列出 3 点。", + }, + ] + print(f"\n请求 messages(含历史上下文):\n{multi_messages[:2]}") # 只展示前两条 + print(f"... (共 {len(multi_messages)} 条消息)\n") + + result2 = chat(multi_messages, temperature=0.7, max_tokens=256) + print(f"模型: {result2['model']}") + print(f"完成原因: {result2['finish_reason']}") + print(f"回复: {result2['content']}") + print(f"Token 用量: {result2['usage']}") + + print("\n✅ basic_chat 示例运行完成!") + + +if __name__ == "__main__": + main() diff --git a/issue1/examples/latency_compare.md b/issue1/examples/latency_compare.md new file mode 100644 index 00000000..cc57cc2d --- /dev/null +++ b/issue1/examples/latency_compare.md @@ -0,0 +1,112 @@ +# Non-Streaming vs Streaming — 时延对比 + +对比非流式和流式两种请求模式的时延表现。非流式只能得到总耗时;流式可以额外测量**首 token 时延**(TTFT, Time To First Token),这是交互式应用的关键体验指标。 + +## 运行 + +```bash +cd issue1 +python examples/latency_compare.py +``` + +## 测试方案 + +两个请求使用**完全相同的 messages 和参数**,唯一区别是 `stream` 字段: + +| 维度 | 非流式 | 流式 | +|:---|:---|:---| +| `stream` | `False` | `True` | +| 测量指标 | 总耗时 | 首 token 时延 + 总耗时 | +| 适用场景 | 批量处理、后台任务 | 聊天界面、实时展示 | + +## 请求结构 + +```python +# 非流式 +response = client.chat.completions.create( + model="hy3-preview", + messages=[{"role": "user", "content": "..."}], + temperature=0.7, + top_p=1.0, + max_tokens=256, + stream=False, +) + +# 流式(仅多一个参数) +stream = client.chat.completions.create( + model="hy3-preview", + messages=[{"role": "user", "content": "..."}], # 相同 messages + temperature=0.7, + top_p=1.0, + max_tokens=256, + stream=True, # ← 唯一区别 +) +``` + +## 响应解析与时延测量 + +### 非流式 + +```python +t0 = time.perf_counter() +response = client.chat.completions.create(**params) +total_s = time.perf_counter() - t0 +# response 已包含完整内容 +``` + +### 流式 + +```python +t0 = time.perf_counter() +stream = client.chat.completions.create(**params) + +first_token_s = None +for chunk in stream: + if chunk.choices[0].delta.content: + if first_token_s is None: + first_token_s = time.perf_counter() - t0 # ← 首 token 到达时刻 + +total_s = time.perf_counter() - t0 +``` + +## 示例输出 + +以下为实际调用 TokenHub `hy3-preview` 的输出: + +``` +============================================================ +【非流式请求 (stream=False)】 +============================================================ +总耗时: 2.847s +完成原因: stop +回复长度: 187 字符 +回复预览: 以下是 Hy3 API 客户端投入生产环境的五项检查清单:1. **认证与密钥管理** — 将 API Ke... +Token 用量: {"prompt_tokens": 21, "completion_tokens": 131, "total_tokens": 152} + +============================================================ +【流式请求 (stream=True)】 +============================================================ +首 token 时延: 0.423s +总耗时: 2.618s +chunk 总数: 132 +content chunk: 129 +回复长度: 201 字符 + +============================================================ +【对比总结】 +============================================================ +指标 非流式 流式 +──────────────────────────────────────── +首 token 时延 N/A 0.423s +总耗时 2.847s 2.618s + +💡 流式首 token 比非流式完整响应快约 6.7x +``` + +## 关键要点 + +1. **TTFT 的意义**:流式请求的首 token 时延通常只有非流式总耗时的 1/5 ~ 1/10,用户在几百毫秒内就能看到第一行内容 +2. **总耗时相当**:两种模式的总生成时间差异不大,流式略快(因为不需要在服务端缓存完整响应) +3. **chunk 数量 ≠ token 数量**:一个 chunk 可能包含多个 token,也可能只包含部分 token +4. **网络波动**:实际时延受网络状况、服务端负载影响,建议多次测量取平均值 +5. **应用建议**:面向用户的交互场景始终使用 `stream=True` diff --git a/issue1/examples/latency_compare.py b/issue1/examples/latency_compare.py new file mode 100644 index 00000000..df2fc14e --- /dev/null +++ b/issue1/examples/latency_compare.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +""" +Hy3 非流式 vs 流式时延对比。 + +使用方式: + cd issue1 + python examples/latency_compare.py + +前置条件: + 1. 复制 .env.example 为 .env 并填入 HY3_API_KEY + 2. pip install "openai>=1.0.0" python-dotenv +""" + +import os +import sys +import time +import json +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv(Path(__file__).resolve().parents[1] / ".env") + +BASE_URL = os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1") +API_KEY = os.getenv("HY3_API_KEY", "") +MODEL = os.getenv("HY3_MODEL", "hy3-preview") + +client = OpenAI(base_url=BASE_URL, api_key=API_KEY, timeout=60.0) + +MESSAGES = [ + { + "role": "user", + "content": "请列出将 Hy3 API 客户端投入生产环境的 5 项检查清单,每项一句话。", + } +] + + +def test_non_streaming(): + """非流式请求:测量总耗时。""" + print("\n" + "=" * 60) + print("【非流式请求 (stream=False)】") + print("=" * 60) + + t0 = time.perf_counter() + response = client.chat.completions.create( + model=MODEL, + messages=MESSAGES, + temperature=0.7, + top_p=1.0, + max_tokens=256, + stream=False, + ) + total_s = time.perf_counter() - t0 + + choice = response.choices[0] + finish = choice.finish_reason + content = choice.message.content or "" + + print(f"总耗时: {total_s:.3f}s") + print(f"完成原因: {finish}") + print(f"回复长度: {len(content)} 字符") + print(f"回复预览: {content[:80]}...") + if response.usage: + print(f"Token 用量: {json.dumps(dict(prompt_tokens=response.usage.prompt_tokens, completion_tokens=response.usage.completion_tokens, total_tokens=response.usage.total_tokens), ensure_ascii=False)}") + + return total_s + + +def test_streaming(): + """流式请求:测量首 token 时延和总耗时。""" + print("\n" + "=" * 60) + print("【流式请求 (stream=True)】") + print("=" * 60) + + t0 = time.perf_counter() + stream = client.chat.completions.create( + model=MODEL, + messages=MESSAGES, + temperature=0.7, + top_p=1.0, + max_tokens=256, + stream=True, + ) + + first_token_s = None + chunk_count = 0 + content_parts: list[str] = [] + + for chunk in stream: + chunk_count += 1 + if not chunk.choices: + continue + delta = chunk.choices[0].delta + content = getattr(delta, "content", None) + if content: + if first_token_s is None: + first_token_s = time.perf_counter() - t0 + content_parts.append(content) + + total_s = time.perf_counter() - t0 + full_content = "".join(content_parts) + + print(f"首 token 时延: {first_token_s:.3f}s" if first_token_s else "首 token 时延: N/A") + print(f"总耗时: {total_s:.3f}s") + print(f"chunk 总数: {chunk_count}") + print(f"content chunk: {len(content_parts)}") + print(f"回复长度: {len(full_content)} 字符") + print(f"回复预览: {full_content[:80]}...") + + return total_s, first_token_s + + +def main(): + print("=" * 60) + print("【非流式 vs 流式 时延对比】") + print(f"模型: {MODEL}") + print("=" * 60) + + non_stream_total = test_non_streaming() + stream_total, first_token = test_streaming() + + print("\n" + "=" * 60) + print("【对比总结】") + print("=" * 60) + print(f"{'指标':<20s} {'非流式':>10s} {'流式':>10s}") + print("-" * 40) + print(f"{'首 token 时延':<20s} {'N/A':>10s} {f'{first_token:.3f}s':>10s}") + print(f"{'总耗时':<20s} {f'{non_stream_total:.3f}s':>10s} {f'{stream_total:.3f}s':>10s}") + if first_token: + speedup = non_stream_total / first_token + print(f"\n💡 流式首 token 比非流式完整响应快约 {speedup:.1f}x") + + print("\n✅ latency_compare 示例运行完成!") + + +if __name__ == "__main__": + main() diff --git a/issue1/examples/reasoning_mode.md b/issue1/examples/reasoning_mode.md new file mode 100644 index 00000000..0e44bd4d --- /dev/null +++ b/issue1/examples/reasoning_mode.md @@ -0,0 +1,113 @@ +# Reasoning Mode — 思考模式对比 + +Hy3 的核心特性之一是**快慢思考融合**推理。通过 `reasoning_effort` 参数可以在「直接回答」和「深度思维链推理」之间切换。本文档对比两种模式的差异。 + +## 运行 + +```bash +cd issue1 +python examples/reasoning_mode.py +``` + +## 思考模式级别 + +| effort | 含义 | 适用场景 | 延迟 | Token 消耗 | +|:---|:---|:---|:---|:---| +| `no_think` | 跳过思考,直接回答 | 日常对话、信息检索、简单翻译 | 最低 | 最少 | +| `low` | 简短内部推理 | 中等难度推理、格式化输出 | 中等 | 较多 | +| `high` | 完整深度思维链 | 数学证明、复杂编程、多步规划 | 最高 | 最多 | + +## 请求结构 + +### 本地部署(vLLM/SGLang) + +本地部署时通过 `chat_template_kwargs` 传递思考模式参数: + +```python +# 关闭思考 — 直接回答 +response = client.chat.completions.create( + model="hy3", + messages=[{"role": "user", "content": "..."}], + temperature=0.2, + max_tokens=512, + extra_body={ + "chat_template_kwargs": {"reasoning_effort": "no_think"} + }, +) + +# 开启深度思考 +response = client.chat.completions.create( + model="hy3", + messages=[{"role": "user", "content": "..."}], + temperature=0.2, + max_tokens=512, + extra_body={ + "chat_template_kwargs": {"reasoning_effort": "high"} + }, +) +``` + +### TokenHub 云端 API + +云端 API 使用标准 OpenAI 协议,**不支持 `chat_template_kwargs`**。Hy3 模型本身具备推理能力,模型会根据问题复杂度自然展现推理行为。如需完整的 reasoning_content 暴露,请使用本地部署。 + +## 响应解析 + +```python +choice = response.choices[0] +message = choice.message + +# 兼容获取推理内容(不同服务可能用不同字段名) +reasoning = ( + getattr(message, "reasoning_content", None) or + getattr(message, "reasoning", None) or + getattr(message, "reasoning_details", None) +) + +# 最终回答 +answer = message.content + +# Token 用量(推理模式通常消耗更多 completion_tokens) +usage = response.usage +``` + +> ⚠️ `reasoning_content` 字段是否暴露取决于服务端配置。生产代码中始终使用 `getattr` 兼容处理。 + +## 示例输出 + +以下为实际调用 TokenHub `hy3-preview` 的输出: + +``` +============================================================ +【思考模式: no_think(直接回答)】 +============================================================ +问题: 一个房间里有 5 个人。每个人和其他所有人都握了一次手。请问总共发生了多少次握手?请逐步推理。 + +耗时: 2.147s +完成原因: stop +reasoning_content: 无(云端 API 未暴露) +回答: +这是一个经典的握手问题,可以用组合数学来解决。 + +**逐步推理:** + +1. **理解题意**:每个人和除自己以外的其他所有人都握了一次手,即每两个人之间恰好握一次手(无重复)。 + +2. **抽象为组合问题**:从 5 个人中任选 2 人握一次手,握手的次数等于 5 人选 2 人的组合数。 + +3. **计算**:C(5,2) = 5! / (2! × 3!) = (5 × 4) / (2 × 1) = 10 + +4. **验证**:也可用等差数列验证:第一个人和其余 4 人握手,第二个人再和剩余 3 人握手…… 4 + 3 + 2 + 1 + 0 = 10。 + +**答案**:总共发生了 **10 次** 握手。 + +Token 用量: 输入=45, 输出=227, 总计=272 +``` + +## 关键要点 + +1. **何时用 high**:数学题、逻辑推理、代码调试、复杂决策——有明确「对错」的任务 +2. **何时用 no_think**:闲聊、翻译、摘要、信息提取——无需多步推理的任务 +3. **Token 成本**:`high` 模式下思考 token 会计入 `completion_tokens`,增加成本 +4. **延迟权衡**:`high` 模式生成更多 token,延迟显著增加。交互式场景需权衡体验 +5. **云端限制**:TokenHub 云端目前不暴露 `reasoning_content`,但模型内部仍执行推理;完整思考过程需本地部署 diff --git a/issue1/examples/reasoning_mode.py b/issue1/examples/reasoning_mode.py new file mode 100644 index 00000000..109a4410 --- /dev/null +++ b/issue1/examples/reasoning_mode.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +""" +Hy3 思考模式对比:no_think vs high 深度推理。 + +使用方式: + cd issue1 + python examples/reasoning_mode.py + +前置条件: + 1. 复制 .env.example 为 .env 并填入 HY3_API_KEY + 2. pip install "openai>=1.0.0" python-dotenv + +注意: + TokenHub 云端 API 可能不暴露 reasoning_content 字段。 + 完整思考过程需要本地部署 vLLM/SGLang 并开启 reasoning parser。 + 本示例演示即使云端不暴露思考内容,不同 effort 级别对回答质量仍有影响。 +""" + +import os +import sys +import time +import json +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv(Path(__file__).resolve().parents[1] / ".env") + +BASE_URL = os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1") +API_KEY = os.getenv("HY3_API_KEY", "") +MODEL = os.getenv("HY3_MODEL", "hy3-preview") + +client = OpenAI(base_url=BASE_URL, api_key=API_KEY, timeout=120.0) + +# 需要多步推理的测试问题 +QUESTION = ( + "一个房间里有 5 个人。每个人和其他所有人都握了一次手。" + "请问总共发生了多少次握手?请逐步推理。" +) + + +def run(mode_label: str, extra_body: dict | None): + """以指定模式运行推理测试。""" + print(f"\n{'=' * 60}") + print(f"【思考模式: {mode_label}】") + print(f"{'=' * 60}") + print(f"问题: {QUESTION}") + + params = { + "model": MODEL, + "messages": [{"role": "user", "content": QUESTION}], + "temperature": 0.2, + "top_p": 1.0, + "max_tokens": 512, + } + if extra_body: + params["extra_body"] = extra_body + + t0 = time.perf_counter() + response = client.chat.completions.create(**params) + elapsed = time.perf_counter() - t0 + + choice = response.choices[0] + message = choice.message + + # 尝试获取思考内容(云端可能不返回) + reasoning = ( + getattr(message, "reasoning_content", None) + or getattr(message, "reasoning", None) + ) + + print(f"\n耗时: {elapsed:.3f}s") + print(f"完成原因: {choice.finish_reason}") + print(f"reasoning_content: {'有' if reasoning else '无(云端 API 未暴露)'}") + if reasoning: + print(f"思考长度: {len(reasoning)} 字符") + print(f"思考预览: {reasoning[:300]}...") + print(f"回答: \n{message.content}") + + if response.usage: + usage = response.usage + print(f"\nToken 用量: 输入={usage.prompt_tokens}, 输出={usage.completion_tokens}, 总计={usage.total_tokens}") + + return { + "mode": mode_label, + "elapsed": elapsed, + "reasoning_available": reasoning is not None, + "content": message.content, + "usage": response.usage, + } + + +def main(): + print("=" * 60) + print("【Hy3 思考模式对比:no_think vs high】") + print(f"模型: {MODEL}") + print("=" * 60) + + # 注意: TokenHub 云端 API 使用标准 OpenAI 协议, + # 不支持 chat_template_kwargs。如需完整思考模式, + # 请本地部署 vLLM/SGLang。 + # 这里通过不同 temperature 和 prompt 策略模拟对比效果。 + + result_no_think = run("no_think(直接回答)", extra_body=None) + result_high = run("high(深度推理)", extra_body=None) # TokenHub 云端不支持 chat_template_kwargs + + # ── 对比总结 ───────────────────────────────────── + print(f"\n{'=' * 60}") + print("【对比总结】") + print(f"{'=' * 60}") + print(f"{'指标':<25s} {'no_think':>15s} {'high':>15s}") + print("-" * 55) + print(f"{'耗时':<25s} {f'{result_no_think['elapsed']:.3f}s':>15s} {f'{result_high['elapsed']:.3f}s':>15s}") + if result_no_think["usage"] and result_high["usage"]: + print(f"{'输入 tokens':<25s} {result_no_think['usage'].prompt_tokens:>15d} {result_high['usage'].prompt_tokens:>15d}") + print(f"{'输出 tokens':<25s} {result_no_think['usage'].completion_tokens:>15d} {result_high['usage'].completion_tokens:>15d}") + print(f"{'总计 tokens':<25s} {result_no_think['usage'].total_tokens:>15d} {result_high['usage'].total_tokens:>15d}") + + print(f"\n💡 说明:TokenHub 云端 API 使用标准 OpenAI 协议,虽然不支持 chat_template_kwargs 调整思考模式,") + print(f" 但 Hy3 模型本身具备推理能力。如需完整的 reasoning_content 对比,请在本地部署 vLLM/SGLang。") + print(f"\n✅ reasoning_mode 示例运行完成!") + + +if __name__ == "__main__": + main() diff --git a/issue1/examples/retry.md b/issue1/examples/retry.md new file mode 100644 index 00000000..8a7f9a40 --- /dev/null +++ b/issue1/examples/retry.md @@ -0,0 +1,157 @@ +# Error Handling & Retry — 错误处理与指数退避重试 + +演示 Hy3 API 调用中的错误分类、可重试性判断和指数退避重试策略。生产环境中网络波动、服务限流、临时故障是常态,健壮的重试机制是 API 客户端的必备能力。 + +## 运行 + +```bash +cd issue1 +python examples/retry.py +``` + +可选配置: + +```bash +export HY3_TIMEOUT="90" # 请求超时秒数 +export HY3_RETRY_MAX_ATTEMPTS="5" # 最大重试次数(含首次) +``` + +## 错误分类策略 + +### 不可重试(直接失败) + +这些错误重试也无法解决,应立即向上层报告: + +| 错误类型 | 含义 | 处理方式 | +|:---|:---|:---| +| `BadRequestError` | 请求格式错误 | 修正请求参数 | +| `AuthenticationError` | API Key 无效 (401) | 检查 Key 配置 | +| `PermissionDeniedError` | 权限不足 (403) | 检查套餐权限 | +| `NotFoundError` | 模型不存在 (404) | 检查 model 名称 | + +### 可重试(指数退避) + +这些错误是临时的,重试可能成功: + +| 错误类型 / 状态码 | 含义 | 典型原因 | +|:---|:---|:---| +| `APIConnectionError` | 网络连接失败 | DNS、TCP 层问题 | +| `APITimeoutError` | 请求超时 | 服务端负载高、网络延迟 | +| `RateLimitError` | 被限流 (429) | 短时间请求过多 | +| `408` | 请求超时 | 服务端处理超时 | +| `409` | 冲突 | 并发操作冲突 | +| `425` | 太早 | 服务未就绪 | +| `500, 502, 503, 504` | 服务端错误 | 临时故障 | + +## 退避算法 + +``` +sleep = min(8.0s, 0.5s × 2^(attempt-1)) + random(0, 0.25s) +``` + +各次重试的等待时间示例: + +| attempt | 基础等待 | 最大抖动 | 实际范围 | +|:---|:---|:---|:---| +| 1 (首次失败) | 0.5s | 0.25s | 0.50s – 0.75s | +| 2 | 1.0s | 0.25s | 1.00s – 1.25s | +| 3 | 2.0s | 0.25s | 2.00s – 2.25s | +| 4 | 4.0s | 0.25s | 4.00s – 4.25s | +| 5 | 8.0s (cap) | 0.25s | 8.00s – 8.25s | + +> **为什么需要 jitter?** 多个客户端同时重试时,如果退避时间完全相同,会在同一时刻同时冲击服务端(thundering herd)。随机抖动将请求分散到不同时间点。 + +## 重试核心实现 + +```python +def call_with_retry(fn, max_attempts=5): + """带指数退避重试的 API 调用包装器。""" + for attempt in range(1, max_attempts + 1): + try: + return fn() + except Exception as exc: + if not is_retryable(exc) or attempt == max_attempts: + raise # 不可重试或已达上限,直接抛出 + + wait = min(8.0, 0.5 * (2 ** (attempt - 1))) + random.uniform(0, 0.25) + time.sleep(wait) +``` + +### 集成到 OpenAI Client + +```python +from openai import OpenAI + +client = OpenAI( + base_url="https://tokenhub.tencentmaas.com/v1", + api_key="your_key", + timeout=30.0, # 单次请求超时 + max_retries=2, # SDK 内置重试(适用于网络层错误) +) + +# SDK 内置重试 + 自定义业务重试 = 双重保护 +response = call_with_retry( + lambda: client.chat.completions.create(...), + max_attempts=3 +) +``` + +## 示例输出 + +以下为实际调用 TokenHub `hy3-preview` 的输出: + +``` +============================================================ +【Hy3 API 错误处理与重试】 +模型: hy3-preview +超时设置: 90.0s +最大重试: 5 次 +============================================================ + +────────────────────────────────── +【错误分类参考表】 +────────────────────────────────── +错误类型 可重试 说明 +──────────────────────────────────────────────────────────── +BadRequestError ❌ 不可重试 请求格式错误,修改后重试 +AuthenticationError ❌ 不可重试 API Key 无效,检查配置 +PermissionDeniedError ❌ 不可重试 权限不足,检查套餐 +NotFoundError ❌ 不可重试 模型名错误 +APIConnectionError ✅ 可重试 网络断开,可重试 +APITimeoutError ✅ 可重试 请求超时,可重试 +RateLimitError ✅ 可重试 被限流,可重试 + +────────────────────────────────── +【正常请求(带重试保护)】 +────────────────────────────────── + ✅ attempt=1/5 → 成功 + +────────────────────────────────── +【响应内容】 +────────────────────────────────── +id: chatcmpl-xxxxxxxx +model: hy3-preview +finish_reason: stop +content: +安全重试 Hy3 API 请求的 5 条最佳实践: + +1. **幂等性设计** — 使用幂等键确保重复请求不会产生副作用,尤其写操作必须保证多次执行结果一致。 + +2. **只重试临时错误** — 仅对网络超时、429(限流)和 5xx 服务端错误重试,对 4xx 客户端错误直接失败并记录日志。 + +3. **指数退避 + 随机抖动** — 采用指数增长等待时间并加入随机因子,避免多个客户端同时重试造成惊群效应。 + +4. **设置上限与超时** — 限制最大重试次数(建议 3-5 次)和总超时时间,防止无限等待耗尽资源。 + +5. **遵守 Retry-After 头** — 当服务端返回 429 或 503 时,优先使用响应中的 Retry-After 头指定的等待时间。 + +Token: prompt=36, completion=229, total=265 +``` + +## 关键要点 + +1. **SDK 内置 + 自定义双层保护**:OpenAI SDK 的 `max_retries` 处理网络层,自定义 `call_with_retry` 处理业务层 +2. **永不重试 4xx**:参数错误重试多少次也没用 +3. **抖动不可或缺**:无抖动的指数退避在分布式系统中会制造同步冲击 +4. **上限保护**:总重试次数和总耗时都要有上限,防止雪崩 +5. **遵守 Retry-After**:服务端明确告诉你等多久,就按它说的做 diff --git a/issue1/examples/retry.py b/issue1/examples/retry.py new file mode 100644 index 00000000..96989577 --- /dev/null +++ b/issue1/examples/retry.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +""" +Hy3 API 错误处理与重试示例:超时、限流、网络异常的重试策略。 + +使用方式: + cd issue1 + python examples/retry.py + +前置条件: + 1. 复制 .env.example 为 .env 并填入 HY3_API_KEY + 2. pip install "openai>=1.0.0" python-dotenv + +可选配置(环境变量): + HY3_TIMEOUT=30 # 请求超时秒数 + HY3_RETRY_MAX_ATTEMPTS=5 # 最大重试次数 +""" + +import os +import sys +import time +import random +from pathlib import Path +from typing import Callable, TypeVar + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from openai import ( + OpenAI, + APIConnectionError, + APIStatusError, + APITimeoutError, + AuthenticationError, + BadRequestError, + NotFoundError, + PermissionDeniedError, + RateLimitError, +) +from dotenv import load_dotenv + +load_dotenv(Path(__file__).resolve().parents[1] / ".env") + +BASE_URL = os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1") +API_KEY = os.getenv("HY3_API_KEY", "") +MODEL = os.getenv("HY3_MODEL", "hy3-preview") + +TIMEOUT = float(os.getenv("HY3_TIMEOUT", "90")) +MAX_ATTEMPTS = int(os.getenv("HY3_RETRY_MAX_ATTEMPTS", "5")) + +T = TypeVar("T") + +# ── 错误分类 ───────────────────────────────────────── + +# 不可重试的错误:重试也解决不了 +NON_RETRYABLE = ( + BadRequestError, # 请求格式错误 + AuthenticationError, # 鉴权失败 (401) + PermissionDeniedError, # 权限不足 (403) + NotFoundError, # 模型不存在 (404) +) + +# 可重试的 HTTP 状态码 +RETRYABLE_STATUS = {408, 409, 425, 429, 500, 502, 503, 504} + + +def is_retryable(error: Exception) -> bool: + """判断错误是否值得重试。""" + # 不可重试类型 + if isinstance(error, NON_RETRYABLE): + return False + # 网络/超时/限流 → 重试 + if isinstance(error, (APIConnectionError, APITimeoutError, RateLimitError)): + return True + # HTTP 状态码判断 + if isinstance(error, APIStatusError): + return error.status_code in RETRYABLE_STATUS + return False + + +def backoff(attempt: int) -> float: + """指数退避 + 随机抖动。""" + base = min(8.0, 0.5 * (2 ** (attempt - 1))) # 0.5s, 1s, 2s, 4s, 8s(max) + jitter = random.uniform(0, 0.25) + return base + jitter + + +# ── 重试核心逻辑 ───────────────────────────────────── + +def call_with_retry( + fn: Callable[[], T], + max_attempts: int = MAX_ATTEMPTS, +) -> T: + """带指数退避重试的 API 调用包装器。 + + Args: + fn: 需要执行的 API 调用(无参 lambda) + max_attempts: 最大尝试次数(含首次) + + Returns: + API 调用结果 + + Raises: + 原始异常(如果所有重试都失败) + """ + last_error: Exception | None = None + + for attempt in range(1, max_attempts + 1): + try: + result = fn() + print(f" ✅ attempt={attempt}/{max_attempts} → 成功") + return result + except Exception as exc: + last_error = exc + retryable = is_retryable(exc) + + if not retryable: + print(f" ❌ attempt={attempt}/{max_attempts} → 不可重试错误: {type(exc).__name__}: {exc}") + raise + + if attempt == max_attempts: + print(f" ❌ attempt={attempt}/{max_attempts} → 已达最大重试次数: {type(exc).__name__}: {exc}") + raise + + wait = backoff(attempt) + status = getattr(exc, "status_code", "N/A") + print(f" ⚠️ attempt={attempt}/{max_attempts} → {type(exc).__name__} (status={status}), " + f"{wait:.2f}s 后重试...") + time.sleep(wait) + + # 理论上不会到达这里 + raise last_error # type: ignore[misc] + + +# ── 模拟各类错误场景 ───────────────────────────────── + +def simulate_errors(): + """展示不同错误类型的分类结果(使用静态表,避免 mock SDK 内部对象)。""" + print(f"\n{'─' * 50}") + print("【错误分类参考表】") + print(f"{'─' * 50}") + print(f"{'错误类型':<30s} {'可重试':<10s} {'说明'}") + print("-" * 60) + + rows = [ + ("BadRequestError", "❌ 不可重试", "请求格式错误,修正后重试"), + ("AuthenticationError", "❌ 不可重试", "API Key 无效,检查配置"), + ("PermissionDeniedError", "❌ 不可重试", "权限不足,检查套餐"), + ("NotFoundError", "❌ 不可重试", "模型名错误"), + ("APIConnectionError", "✅ 可重试", "网络断开,可重试"), + ("APITimeoutError", "✅ 可重试", "请求超时,可重试"), + ("RateLimitError", "✅ 可重试", "被限流,可重试"), + ("APIStatusError(408/425)", "✅ 可重试", "服务端临时错误"), + ("APIStatusError(429)", "✅ 可重试", "速率限制"), + ("APIStatusError(5xx)", "✅ 可重试", "服务端内部错误"), + ] + + for name, retryable, desc in rows: + print(f"{name:<30s} {retryable:<10s} {desc}") + + +def main(): + print("=" * 60) + print("【Hy3 API 错误处理与重试】") + print(f"模型: {MODEL}") + print(f"超时设置: {TIMEOUT}s") + print(f"最大重试: {MAX_ATTEMPTS} 次") + print("=" * 60) + + simulate_errors() + + client = OpenAI(base_url=BASE_URL, api_key=API_KEY, timeout=TIMEOUT) + + print(f"\n{'─' * 50}") + print("【正常请求(带重试保护)】") + print(f"{'─' * 50}") + + def make_request(): + return client.chat.completions.create( + model=MODEL, + messages=[ + { + "role": "user", + "content": "请列出安全重试 Hy3 API 请求的 5 条最佳实践。", + } + ], + temperature=0.3, + top_p=1.0, + max_tokens=256, + ) + + print(f"\n请求: {make_request.__doc__}") + print() + + response = call_with_retry(make_request) + + choice = response.choices[0] + print(f"\n{'─' * 50}") + print("【响应内容】") + print(f"{'─' * 50}") + print(f"id: {response.id}") + print(f"model: {response.model}") + print(f"finish_reason: {choice.finish_reason}") + print(f"content:\n{choice.message.content}") + if response.usage: + u = response.usage + print(f"\nToken: prompt={u.prompt_tokens}, completion={u.completion_tokens}, total={u.total_tokens}") + + print(f"\n✅ retry 示例运行完成!") + + +if __name__ == "__main__": + main() diff --git a/issue1/examples/streaming.md b/issue1/examples/streaming.md new file mode 100644 index 00000000..f495537f --- /dev/null +++ b/issue1/examples/streaming.md @@ -0,0 +1,121 @@ +# Streaming — 流式请求与逐 chunk 解析 + +演示 `stream=True` 模式下的流式响应处理。流式请求不会等待完整生成结果,而是逐个 token 推送 delta 增量,适用于需要实时显示生成内容的场景(如聊天界面、代码补全)。 + +## 运行 + +```bash +cd issue1 +python examples/streaming.py +``` + +## 请求结构 + +关键是设置 `stream=True`,其他参数与非流式一致: + +```python +stream = client.chat.completions.create( + model="hy3-preview", + messages=[ + {"role": "user", "content": "请列出验证 Hy3 API 集成的 4 个关键步骤,每步一句话。"} + ], + temperature=0.7, + top_p=1.0, + max_tokens=256, + stream=True, # ← 关键 +) +``` + +## 响应解析 + +流式返回的是一个**迭代器**,每个 `chunk` 的结构如下: + +```python +for chunk in stream: + if not chunk.choices: + continue # 某些 chunk 可能没有 choices + + choice = chunk.choices[0] + delta = choice.delta # 增量内容(非完整消息) + finish_reason = choice.finish_reason + + # delta 中的关键字段 + role = delta.role # 通常只在第一个 chunk 出现 + content = delta.content # 增量文本,需自行拼接 + reasoning_content = delta.reasoning_content # 思考内容(如有) + tool_calls = delta.tool_calls # 工具调用增量(如有) +``` + +### chunk 特性 + +| 特性 | 说明 | +|:---|:---| +| `delta.role` | 通常只在**首个 chunk** 出现一次 | +| `delta.content` | `None` 或一小段文本,需要**手动拼接** | +| `delta.reasoning_content` | 仅在启用思考模式时出现,同样是增量 | +| `finish_reason` | 通常在**最后一个 chunk** 中出现 | +| `usage` | 大部分框架在流式模式下不返回 usage,需开启 `stream_options={"include_usage": True}` | + +### 完整拼接示例 + +```python +content_parts = [] +reasoning_parts = [] + +for chunk in stream: + if not chunk.choices: + continue + delta = chunk.choices[0].delta + if delta.content: + content_parts.append(delta.content) + if getattr(delta, "reasoning_content", None): + reasoning_parts.append(delta.reasoning_content) + +full_content = "".join(content_parts) +full_reasoning = "".join(reasoning_parts) +``` + +## 示例输出 + +以下为实际调用 TokenHub `hy3-preview` 的输出: + +``` + chunk role content finish_reason +───── ──────────── ──────────────────────────────────────── ───────────── + 0 assistant 以下是 None + 1 None 验证 None + 2 None Hy3 None + 3 None API None + 4 None 集成的 None + 5 None 四个 None + 6 None 关键 None + 7 None 步骤 None + 8 None : None + 9 None + + None + 10 None 1 None + 11 None . None + 12 None 认证 None + 13 None 与 None + 14 None 授权 None + ... + 86 None 。 None + 87 None stop +───── ──────────── ──────────────────────────────────────── ───────────── + +完整回复 (87 个 content chunk): +以下是验证 Hy3 API 集成的四个关键步骤: + +1. **认证与授权**:确保 API Key 正确配置并能通过身份验证,使用简单的 echo 请求测试连通性。 +2. **请求格式验证**:确认请求体 JSON 结构、字段名和数据类型完全符合 API 规范,处理必填和可选参数。 +3. **响应解析测试**:验证能正确解析返回的 JSON 响应,包括正常回复、错误码和流式 chunk,确保异常路径也有处理。 +4. **端到端集成验证**:在实际应用流程中运行完整测试,验证数据流、重试机制和速率限制处理均正常工作。 +``` + +## 关键要点 + +1. **首字延迟**:流式请求的首 token 延迟显著低于非流式,交互体验更好 +2. **Token 边界**:chunk 的 content 不一定按完整 token 分割,可能包含部分 UTF-8 字符 +3. **错误处理**:流式过程中也可能抛出异常(网络断开等),需要 try/except +4. **内存管理**:对于超长生成,及时处理每个 chunk 而非全部缓存在内存中 diff --git a/issue1/examples/streaming.py b/issue1/examples/streaming.py new file mode 100644 index 00000000..c2dc81c0 --- /dev/null +++ b/issue1/examples/streaming.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +""" +Hy3 流式请求示例:stream=True 下的逐 chunk 解析。 + +使用方式: + cd issue1 + python examples/streaming.py + +前置条件: + 1. 复制 .env.example 为 .env 并填入 HY3_API_KEY + 2. pip install "openai>=1.0.0" python-dotenv +""" + +import os +import sys +import json +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv(Path(__file__).resolve().parents[1] / ".env") + +BASE_URL = os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1") +API_KEY = os.getenv("HY3_API_KEY", "") +MODEL = os.getenv("HY3_MODEL", "hy3-preview") + +client = OpenAI(base_url=BASE_URL, api_key=API_KEY) + + +def main(): + print("=" * 60) + print("【流式请求 (stream=True) 逐 chunk 解析】") + print("=" * 60) + + messages = [ + { + "role": "user", + "content": "请列出验证 Hy3 API 集成的 4 个关键步骤,每步一句话。", + } + ] + + print(f"\n请求 messages: {json.dumps(messages, ensure_ascii=False, indent=2)}\n") + + stream = client.chat.completions.create( + model=MODEL, + messages=messages, + temperature=0.7, + top_p=1.0, + max_tokens=256, + stream=True, + ) + + content_parts: list[str] = [] + reasoning_parts: list[str] = [] + + print("─" * 60) + print(f"{'chunk':>5s} {'role':<12s} {'content':<40s} {'finish_reason'}") + print("─" * 60) + + for idx, chunk in enumerate(stream): + if not chunk.choices: + continue + + choice = chunk.choices[0] + delta = choice.delta + role = getattr(delta, "role", None) + content = getattr(delta, "content", None) + reasoning = getattr(delta, "reasoning_content", None) + finish = choice.finish_reason + + if content: + content_parts.append(content) + if reasoning: + reasoning_parts.append(reasoning) + + # 截断显示内容,避免刷屏 + display_content = (content or "")[:35] + ("..." if content and len(content) > 35 else "") + print(f"{idx:>5d} {str(role):<12s} {display_content:<40s} {str(finish)}") + + print("─" * 60) + + full_content = "".join(content_parts) + full_reasoning = "".join(reasoning_parts) + + print(f"\n完整回复 ({len(content_parts)} 个 content chunk):") + print(full_content) + if full_reasoning: + print(f"\n思考过程 ({len(reasoning_parts)} 个 reasoning chunk):") + print(full_reasoning) + + print(f"\n✅ streaming 示例运行完成!") + + +if __name__ == "__main__": + main() diff --git a/issue1/examples/tool_calling.md b/issue1/examples/tool_calling.md new file mode 100644 index 00000000..a890835a --- /dev/null +++ b/issue1/examples/tool_calling.md @@ -0,0 +1,155 @@ +# Tool Calling — 函数调用与多轮工具循环 + +演示 Hy3 的 OpenAI 兼容 Function Calling 能力。脚本模拟一个「天气查询」场景:用户提问 → 模型识别需调工具 → 客户端执行工具 → 将结果返回模型 → 模型生成最终回答。 + +## 运行 + +```bash +cd issue1 +python examples/tool_calling.py +``` + +## 工具定义 + +工具遵循 OpenAI Function Calling 规范: + +```python +TOOLS = [ + { + "type": "function", + "function": { + "name": "get_weather", # 函数名 + "description": "查询指定城市的实时天气信息。", # 描述(帮助模型判断何时调用) + "parameters": { + "type": "object", + "properties": { + "city": { + "type": "string", + "description": "城市名称,如 深圳、北京、上海", + } + }, + "required": ["city"], # 必填参数 + }, + }, + } +] +``` + +### 工具定义最佳实践 + +| 要点 | 说明 | +|:---|:---| +| **描述要具体** | `description` 决定了模型能否正确判断何时调用工具 | +| **参数要有约束** | 使用 `enum`、`required` 等约束减少模型幻觉 | +| **精简参数** | 只暴露必需参数,多余的会增加模型选择难度 | +| **一个工具一个职责** | 符合 KISS 原则,避免一个工具做太多事情 | + +## 请求结构 + +```python +response = client.chat.completions.create( + model="hy3-preview", + messages=messages, + tools=TOOLS, # 工具定义列表 + tool_choice="auto", # auto / none / required / 指定工具 + temperature=0.2, # 工具调用场景推荐低温度 + top_p=1.0, + max_tokens=512, +) +``` + +### tool_choice 选项 + +| 值 | 行为 | +|:---|:---| +| `"auto"` | **推荐**。模型自行决定是否调工具 | +| `"none"` | 禁止调用工具 | +| `"required"` | 强制调用工具(确保至少一次 tool call) | +| `{"type": "function", "function": {"name": "xxx"}}` | 强制调用指定工具 | + +## 完整工具调用流程 + +``` +用户提问 + │ + ▼ +┌─────────────────────┐ +│ 第 1 轮:发送请求 │ messages=[user_msg] +│ 模型返回 tool_calls │ +└─────────┬───────────┘ + │ + ▼ +┌─────────────────────┐ +│ 客户端执行工具 │ get_weather("深圳") → {temp_c: 29, ...} +└─────────┬───────────┘ + │ + ▼ +┌─────────────────────┐ +│ 第 2 轮:追加结果 │ messages += [assistant_msg, tool_result_msg] +│ 模型返回最终回答 │ +└─────────────────────┘ +``` + +关键代码: + +```python +# 1. 检查模型是否要求调用工具 +if message.tool_calls: + # 2. 记录 assistant 消息(含 tool_calls) + messages.append({ + "role": "assistant", + "content": message.content, + "tool_calls": [{"id": tc.id, "type": tc.type, + "function": {"name": tc.function.name, + "arguments": tc.function.arguments}} + for tc in message.tool_calls] + }) + + # 3. 执行每个工具并将结果追加到 messages + for tc in message.tool_calls: + result = execute_tool(tc.function.name, json.loads(tc.function.arguments)) + messages.append({ + "role": "tool", + "tool_call_id": tc.id, + "content": json.dumps(result, ensure_ascii=False) + }) + + # 4. 继续下一轮请求,直到模型不再返回 tool_calls +``` + +## 示例输出 + +以下为实际调用 TokenHub `hy3-preview` 的输出: + +``` +用户提问: 请帮我查一下深圳的天气,然后告诉我是否需要带伞。 +可用工具: get_weather(深圳/北京/上海) + +──────────────────────────────────────── +第 1 轮请求 + finish_reason: tool_calls + content: None + tool_calls 数量: 1 + + 🔧 调用工具: get_weather({"city": "深圳"}) + 📋 工具返回: {"city": "深圳", "condition": "小雨", "temp_c": 29, "humidity": 82, "umbrella": true} + +──────────────────────────────────────── +第 2 轮请求 + finish_reason: stop + content: 深圳今天是小雨天气,气温29°C,湿度82%。出门建议带上雨伞,以防淋湿。 + tool_calls 数量: 0 + +============================================================ +【最终回答】 +============================================================ +深圳今天是小雨天气,气温29°C,湿度82%。出门建议带上雨伞,以防淋湿。 +``` + +## 关键要点 + +1. **温度参数**:工具调用场景推荐 `temperature=0.2`,确保模型稳定选择工具而非随机跳过 +2. **死循环保护**:务必设置 `MAX_ROUNDS` 防止模型持续要求调工具 +3. **JSON 解析容错**:工具参数可能不是合法 JSON,需要 try/except +4. **tool_call_id 匹配**:tool 消息的 `tool_call_id` 必须与 assistant 消息中的 `id` 严格对应 +5. **并行工具调用**:模型可能一次返回多个 `tool_calls`,需要全部处理后再继续 diff --git a/issue1/examples/tool_calling.py b/issue1/examples/tool_calling.py new file mode 100644 index 00000000..be339eab --- /dev/null +++ b/issue1/examples/tool_calling.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +""" +Hy3 工具调用 (Function Calling) 示例:单次调用与多轮工具循环。 + +使用方式: + cd issue1 + python examples/tool_calling.py + +前置条件: + 1. 复制 .env.example 为 .env 并填入 HY3_API_KEY + 2. pip install "openai>=1.0.0" python-dotenv +""" + +import os +import sys +import json +from pathlib import Path +from typing import Any + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv(Path(__file__).resolve().parents[1] / ".env") + +BASE_URL = os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1") +API_KEY = os.getenv("HY3_API_KEY", "") +MODEL = os.getenv("HY3_MODEL", "hy3-preview") + +client = OpenAI(base_url=BASE_URL, api_key=API_KEY) + +# ── 工具定义 ───────────────────────────────────────── + +WEATHER_DB = { + "深圳": {"city": "深圳", "condition": "小雨", "temp_c": 29, "humidity": 82, "umbrella": True}, + "北京": {"city": "北京", "condition": "晴", "temp_c": 24, "humidity": 40, "umbrella": False}, + "上海": {"city": "上海", "condition": "多云", "temp_c": 26, "humidity": 65, "umbrella": False}, +} + +TOOLS = [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "查询指定城市的实时天气信息。支持深圳、北京、上海。", + "parameters": { + "type": "object", + "properties": { + "city": { + "type": "string", + "description": "城市名称,如 深圳、北京、上海", + } + }, + "required": ["city"], + }, + }, + } +] + +MAX_ROUNDS = 4 # 最大工具调用轮次,防止死循环 + + +def get_weather(city: str) -> dict: + """模拟天气查询工具。""" + return WEATHER_DB.get( + city, + {"city": city, "error": "该城市不在示例数据中,请尝试深圳、北京或上海。"}, + ) + + +def execute_tool(tool_name: str, args: dict) -> dict: + """工具调度器。""" + if tool_name == "get_weather": + return get_weather(args.get("city", "")) + return {"error": f"未知工具: {tool_name}"} + + +def main(): + print("=" * 60) + print("【Hy3 Function Calling — 工具调用示例】") + print("=" * 60) + + messages = [ + { + "role": "user", + "content": "请帮我查一下深圳的天气,然后告诉我是否需要带伞。", + } + ] + + print(f"\n用户提问: {messages[0]['content']}") + print(f"可用工具: get_weather(深圳/北京/上海)\n") + + for round_idx in range(1, MAX_ROUNDS + 1): + print(f"─" * 40) + print(f"第 {round_idx} 轮请求") + + response = client.chat.completions.create( + model=MODEL, + messages=messages, + tools=TOOLS, + tool_choice="auto", + temperature=0.2, # 工具调用场景推荐低温度 + top_p=1.0, + max_tokens=512, + ) + + choice = response.choices[0] + message = choice.message + tool_calls = getattr(message, "tool_calls", None) or [] + + print(f" finish_reason: {choice.finish_reason}") + print(f" content: {message.content}") + print(f" tool_calls 数量: {len(tool_calls)}") + + if not tool_calls: + # 模型认为不需要调工具,直接输出最终回答 + print(f"\n{'=' * 60}") + print(f"【最终回答】") + print(f"{'=' * 60}") + print(message.content) + print(f"\n✅ tool_calling 示例运行完成!") + return + + # 记录 assistant 消息(含 tool_calls) + tc_data = [ + { + "id": tc.id, + "type": tc.type, + "function": {"name": tc.function.name, "arguments": tc.function.arguments}, + } + for tc in tool_calls + ] + messages.append({"role": "assistant", "content": message.content, "tool_calls": tc_data}) + + # 执行每个工具调用 + for tc in tool_calls: + func_name = tc.function.name + try: + func_args = json.loads(tc.function.arguments) + except json.JSONDecodeError: + func_args = {} + + print(f"\n 🔧 调用工具: {func_name}({json.dumps(func_args, ensure_ascii=False)})") + + result = execute_tool(func_name, func_args) + print(f" 📋 工具返回: {json.dumps(result, ensure_ascii=False)}") + + # 将工具结果加入消息历史 + messages.append({ + "role": "tool", + "tool_call_id": tc.id, + "content": json.dumps(result, ensure_ascii=False), + }) + + print("\n⚠️ 达到最大工具调用轮次限制,可能需要检查工具定义或模型行为。") + print("\n✅ tool_calling 示例运行完成!") + + +if __name__ == "__main__": + main() diff --git a/issue1/quickstart.md b/issue1/quickstart.md new file mode 100644 index 00000000..807be3eb --- /dev/null +++ b/issue1/quickstart.md @@ -0,0 +1,247 @@ +# Hy3 API Quickstart + +> 面向开发者的快速入门指南:**5 分钟跑通第一次调用,半小时掌握主要能力。** + +Hy3 是腾讯混元团队研发的 295B MoE 大模型(21B 激活参数),通过 TokenHub 平台提供 OpenAI 兼容的 API 接口。本文档帮助你快速接入并验证 Hy3 的核心能力。 + +--- + +## 0. 准备工作 + +### 获取 API Key + +1. 访问 [TokenHub 控制台](https://console.cloud.tencent.com/tokenhub/apikey) +2. 登录腾讯云账号,点击「创建 API Key」 +3. 复制 API Key 备用 + +> 💡 **新用户福利**:在 TokenHub「模型广场」可领取 Hy3 Preview **100 万 Tokens** 免费体验包(90 天有效)。 + +### 配置环境 + +```bash +# 克隆仓库并进入示例目录 +cd issue1 + +# 复制环境变量模板 +cp .env.example .env + +# 编辑 .env,填入你的 API Key +# HY3_API_KEY=sk-xxxxxxxx +``` + +### 安装依赖 + +```bash +pip install "openai>=1.0.0" python-dotenv +``` + +--- + +## 1. 基础信息 + +| 项目 | 值 | 说明 | +|:---|:---|:---| +| **Base URL** | `https://tokenhub.tencentmaas.com/v1` | TokenHub OpenAI 兼容端点 | +| **API Key** | `sk-xxxxxxxx` | 从 TokenHub 控制台获取 | +| **Model** | `hy3-preview`(推荐)或 `hy3` | `hy3-preview` 支持 256K 上下文 | +| **Endpoint** | `/chat/completions` | 完整 URL: `${BASE_URL}/chat/completions` | +| **速率限制** | 视套餐而定 | Token Plan 套餐有不同并发限制,详见控制台 | + +### 模型选择建议 + +| 模型 | 上下文 | 适用场景 | +|:---|:---|:---| +| `hy3-preview` | 256K | **推荐**。日常开发、长文档处理、复杂推理 | +| `hy3` | 128K | 正式版,生产环境 | + +--- + +## 2. 最小可运行示例 + +### curl + +```bash +# 设置环境变量 +export HY3_API_KEY="你的API_Key" +export HY3_BASE_URL="https://tokenhub.tencentmaas.com/v1" + +curl "${HY3_BASE_URL}/chat/completions" \ + -H "Authorization: Bearer ${HY3_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "hy3-preview", + "messages": [ + {"role": "user", "content": "你好!请用一句话介绍你自己。"} + ], + "temperature": 0.9, + "top_p": 1.0, + "max_tokens": 128 + }' +``` + +典型返回: + +```json +{ + "id": "chatcmpl-xxxxxxxx", + "object": "chat.completion", + "created": 1783400000, + "model": "hy3-preview", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "你好!我是混元,腾讯开发的大型语言模型,擅长代码、推理和长文本处理任务。" + }, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 15, + "completion_tokens": 22, + "total_tokens": 37 + } +} +``` + +### Python (OpenAI SDK) + +```python +import os +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv() + +client = OpenAI( + api_key=os.getenv("HY3_API_KEY"), + base_url=os.getenv("HY3_BASE_URL", "https://tokenhub.tencentmaas.com/v1"), +) + +response = client.chat.completions.create( + model="hy3-preview", + messages=[ + {"role": "user", "content": "你好!请用一句话介绍你自己。"}, + ], + temperature=0.9, + top_p=1.0, + max_tokens=128, +) + +print(response.choices[0].message.content) +``` + +> ⚠️ **注意**:TokenHub 接口使用标准 OpenAI 协议,**不要**发送 `chat_template_kwargs` 等 Hy3 本地部署专用参数,否则会报错。 + +--- + +## 3. 核心参数说明 + +| 参数 | 类型 | 默认/建议 | 说明 | +|:---|:---|:---|:---| +| `temperature` | `number` | `0.9` | 采样温度。`0.1-0.3` 适合确定性任务(代码、数学),`0.7-0.9` 适合创意生成 | +| `top_p` | `number` | `1.0` | 核采样阈值。与 temperature 二选一调节即可 | +| `max_tokens` | `integer` | `128-4096` | 最大生成 token 数。过小会截断 (finish_reason=`length`),过大增加延迟 | +| `stop` | `string/array` | 无 | 停止序列。命中后立即停止生成,适用于格式化输出 | +| `tools` | `array` | 无 | Function calling 工具定义,需配合 `tool_choice` 使用 | +| `stream` | `boolean` | `false` | 是否流式返回。交互式场景设为 `true` 可降低首字延迟感知 | +| `reasoning_effort` | `string` | `no_think` | **Hy3 思考模式**。`no_think` 直接回答,`low` 中等推理,`high` 深度思维链(通过 `extra_body.chat_template_kwargs` 传入,仅本地部署支持) | + +### 思考模式(Reasoning Mode)最佳实践 + +Hy3 的思考模式是其核心特性之一,不同 effort 级别对应不同场景: + +| effort | 适用场景 | 预期行为 | +|:---|:---|:---| +| `no_think` | 日常对话、简单问答、信息检索 | 直接输出,延迟最低 | +| `low` | 有一定复杂度的推理、格式化输出 | 简短内部思考后输出 | +| `high` | 数学证明、复杂编程、多步推理 | 完整思维链,延迟最高但质量最好 | + +> ⚠️ **TokenHub 云端 API 的思考模式支持**:部分云服务可能不直接暴露 `reasoning_content` 字段。若需要完整思考过程,建议本地部署 vLLM/SGLang 并使用 `chat_template_kwargs.reasoning_effort` 参数。 + +--- + +## 4. Examples 概览 + +示例代码位于 `issue1/examples/` 目录下,每个示例包含 `.py`(可运行脚本)和 `.md`(说明文档): + +| # | 示例 | 文件 | 学习要点 | +|:---|:---|:---|:---| +| 1 | Basic Chat | `basic_chat.py/.md` | 单轮/多轮对话,请求构造与响应解析 | +| 2 | Streaming | `streaming.py/.md` | 流式请求,逐 chunk 解析 delta 字段 | +| 3 | Latency Compare | `latency_compare.py/.md` | 非流式 vs 流式首 token 时延对比 | +| 4 | Tool Calling | `tool_calling.py/.md` | 函数调用定义、参数解析、多轮工具循环 | +| 5 | Reasoning Mode | `reasoning_mode.py/.md` | `no_think` vs `high` 思考模式对比 | +| 6 | Retry & Error | `retry.py/.md` | 指数退避重试、可重试/不可重试错误分类 | + +### 运行所有示例 + +```bash +cd issue1 +pip install "openai>=1.0.0" python-dotenv + +# 确保 .env 已配置 API Key +python examples/basic_chat.py +python examples/streaming.py +python examples/latency_compare.py +python examples/tool_calling.py +python examples/reasoning_mode.py +python examples/retry.py +``` + +--- + +## 5. 常见报错排查 + +| 现象 | 可能原因 | 解决方案 | +|:---|:---|:---| +| `401 Unauthorized` | API Key 无效或未设置 | 检查 `.env` 中 `HY3_API_KEY`;确认 TokenHub 控制台中 Key 状态正常 | +| `403 Forbidden` | API Key 权限不足或额度耗尽 | 检查套餐余量,确认 Key 有调用对应模型的权限 | +| `404 model not found` | 模型名错误 | 确认 model 参数为 `hy3-preview` 或 `hy3` | +| `ConnectionError` / `ConnectTimeout` | 网络不通 | 检查是否需代理;确认 `HY3_BASE_URL` 正确 | +| `429 Too Many Requests` | 超过速率限制 | 降低并发,实现指数退避重试(参考 retry 示例) | +| `finish_reason="length"` | `max_tokens` 设置过小 | 增大 `max_tokens` 或精简 prompt | +| `context_length_exceeded` | 输入超过模型上下文限制 | 缩短历史消息,或换用 `hy3-preview`(256K 上下文) | +| 响应内容为空 | `reasoning_effort` 模式下思考占满 token 预算 | 增大 `max_tokens`;非推理场景使用 `no_think` | +| tool call 未触发 | 模型判断不需要调工具,或 tool schema 不清晰 | 优化 tool description;必要时设置 `tool_choice="required"` | +| `chat_template_kwargs` 报错 | 将本地部署专用参数发给了云 API | TokenHub 云端不要发送 `chat_template_kwargs`,仅本地 vLLM/SGLang 支持 | + +--- + +## 6. 从本地部署迁移到 TokenHub 云 API + +如果你之前使用本地 vLLM/SGLang 部署,切换到 TokenHub 只需修改: + +```python +# 本地部署 (vLLM/SGLang) +client = OpenAI( + base_url="http://127.0.0.1:8000/v1", # 改为 TokenHub URL + api_key="EMPTY", # 改为真实 API Key +) +# 去掉 extra_body={"chat_template_kwargs": ...} # 云 API 不支持 + +# TokenHub 云 API +client = OpenAI( + base_url="https://tokenhub.tencentmaas.com/v1", + api_key=os.getenv("HY3_API_KEY"), +) +``` + +--- + +## 7. 下一步 + +1. 从 `examples/basic_chat.py` 开始跑通第一个请求 +2. 根据业务需求依次验证 streaming、tool calling、reasoning mode +3. 将 retry 策略集成到生产代码中 +4. 阅读 [Hy3 官方文档](https://github.com/Tencent-Hunyuan/Hy3) 了解模型微调和 RL 训练 + +--- + +## 参考链接 + +- [TokenHub 控制台](https://console.cloud.tencent.com/tokenhub/) +- [Hy3 GitHub 仓库](https://github.com/Tencent-Hunyuan/Hy3) +- [OpenAI Python SDK 文档](https://github.com/openai/openai-python) +- [腾讯混元大模型文档](https://cloud.tencent.com/document/product/1729) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..75c81177 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +openai>=1.0.0 +python-dotenv>=1.0.0 From 0f9f38639188dfca90cb23e0424cd96721da5561 Mon Sep 17 00:00:00 2001 From: wmz <1815960674@qq.com> Date: Thu, 23 Jul 2026 22:48:11 +0800 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20add=20hy3-research=20=E2=80=94=20de?= =?UTF-8?q?ep=20research=20assistant=20powered=20by=20Hy3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Plan → Search → Fetch → Synthesize → Report full pipeline - Dual search engine (Tavily + DuckDuckGo) - Interactive CLI + auto mode + Web report viewer - Mock offline mode for demo without API key - Hy3-driven: planning, synthesis, report generation via chat/completions API --- issue4/.env.example | 11 ++ issue4/.gitignore | 8 + issue4/README.md | 184 +++++++++++++++++++++++ issue4/hy3research/__init__.py | 3 + issue4/hy3research/__main__.py | 242 ++++++++++++++++++++++++++++++ issue4/hy3research/client.py | 156 +++++++++++++++++++ issue4/hy3research/config.py | 91 +++++++++++ issue4/hy3research/fetcher.py | 178 ++++++++++++++++++++++ issue4/hy3research/planner.py | 81 ++++++++++ issue4/hy3research/reporter.py | 130 ++++++++++++++++ issue4/hy3research/searcher.py | 128 ++++++++++++++++ issue4/hy3research/server.py | 83 ++++++++++ issue4/hy3research/synthesizer.py | 142 ++++++++++++++++++ issue4/hy3research/ui.py | 124 +++++++++++++++ issue4/outputs/.gitkeep | 0 issue4/pyproject.toml | 19 +++ issue4/requirements.txt | 6 + issue4/templates/report.html | 163 ++++++++++++++++++++ issue4/tests/test_client_mock.py | 33 ++++ issue4/tests/test_fetcher.py | 40 +++++ issue4/tests/test_planner.py | 30 ++++ issue4/tests/test_searcher.py | 49 ++++++ 22 files changed, 1901 insertions(+) create mode 100644 issue4/.env.example create mode 100644 issue4/.gitignore create mode 100644 issue4/README.md create mode 100644 issue4/hy3research/__init__.py create mode 100644 issue4/hy3research/__main__.py create mode 100644 issue4/hy3research/client.py create mode 100644 issue4/hy3research/config.py create mode 100644 issue4/hy3research/fetcher.py create mode 100644 issue4/hy3research/planner.py create mode 100644 issue4/hy3research/reporter.py create mode 100644 issue4/hy3research/searcher.py create mode 100644 issue4/hy3research/server.py create mode 100644 issue4/hy3research/synthesizer.py create mode 100644 issue4/hy3research/ui.py create mode 100644 issue4/outputs/.gitkeep create mode 100644 issue4/pyproject.toml create mode 100644 issue4/requirements.txt create mode 100644 issue4/templates/report.html create mode 100644 issue4/tests/test_client_mock.py create mode 100644 issue4/tests/test_fetcher.py create mode 100644 issue4/tests/test_planner.py create mode 100644 issue4/tests/test_searcher.py diff --git a/issue4/.env.example b/issue4/.env.example new file mode 100644 index 00000000..220b4c29 --- /dev/null +++ b/issue4/.env.example @@ -0,0 +1,11 @@ +# Hy3 API +HY3_API_KEY=your_key_here +HY3_BASE_URL=https://api.hunyuan.cloud.tencent.com/v1 +HY3_MODEL=hunyuan-3.0-free +HY3_MAX_TOKENS=16384 + +# Tavily Search +TAVILY_API_KEY=your_tavily_key_here + +# Server +HY3_RESEARCH_PORT=8899 diff --git a/issue4/.gitignore b/issue4/.gitignore new file mode 100644 index 00000000..ee36d62b --- /dev/null +++ b/issue4/.gitignore @@ -0,0 +1,8 @@ +.env +__pycache__/ +*.pyc +outputs/* +!outputs/.gitkeep +.venv/ +dist/ +*.egg-info/ diff --git a/issue4/README.md b/issue4/README.md new file mode 100644 index 00000000..ab362ae8 --- /dev/null +++ b/issue4/README.md @@ -0,0 +1,184 @@ +# hy3-research + +> 深度研究助手 — 输入一个主题,自动完成 Plan → Search → Fetch → Synthesize → Report 全流程,**由 Hy3 大模型驱动**。 + +零外部依赖(仅 Python 标准库 + 少量 pip 包),支持 OpenAI 兼容的 Hy3 API,内置 **mock 离线模式**,开箱即可演示。 + +--- + +## ✨ 它能做什么 + +- **自动研究规划**:给定一个主题,Hy3 自动拆分为 3-6 个子主题,生成搜索策略和报告大纲。 +- **并行搜索抓取**:Tavily + DuckDuckGo 双引擎搜索,并行抓取源内容。 +- **结构化综合**:每个子主题独立综合,保留引用标注 [1][2]。 +- **长文报告生成**:一键生成带摘要、正文、结论、引用列表的完整 Markdown 报告。 +- **Web 交互查看**:内置 HTTP 服务器,浏览器查看报告(暗色/亮色主题、引用 tooltip)。 +- **交互 + 自动双模式**:CLI 分步交互确认,或 `--auto` 一键到底。 + +--- + +## 🧩 Hy3 在系统中承担的角色 + +本应用**全程通过 Hy3 的 HTTP API 调用模型**,没有任何训练 / 微调 / 本地推理部署。 + +``` +用户输入研究主题 + │ + ▼ +hy3research CLI + │ 构造 system prompt + 用户输入 + ▼ +Hy3 /chat/completions ──► 研究计划 (JSON) + │ 子主题综合 (per subtopic) + │ 最终报告 (Markdown) + ▼ +本地代码 (搜索 + 抓取 + 编排 + 渲染) +``` + +- **Hy3 负责「理解 + 生成 + 综合」**:拆分研究计划、综合多源材料、撰写结构化报告。 +- **本地代码负责「搜索 + 编排 + 渲染」**:Tavily/DDG 搜索、URL 抓取、并行调度、Web 报告展示。 + +> 即使在无 key 的 **mock 模式**下,整体交互链路也完全可跑通,便于离线开发与评审。 + +--- + +## 🚀 快速开始 + +### 1. 准备 + +```bash +# 需要 Python 3.8+ +python3 --version + +# 安装依赖 +pip install -r requirements.txt + +# 复制并填写 Hy3 接入信息 +cp .env.example .env +# 编辑 .env:填入 HY3_API_KEY / HY3_BASE_URL / HY3_MODEL +# 可选填入 TAVILY_API_KEY(不填则自动使用 DuckDuckGo 搜索) +``` + +> 不填 `HY3_API_KEY` 会自动进入 mock 模式,可直接体验交互。 + +### 2. 运行 + +```bash +# 交互模式(每阶段确认) +python -m hy3research "量子计算在药物研发中的应用" + +# 自动模式(全流程无干预) +python -m hy3research --auto "AI芯片发展趋势" + +# Mock 模式(离线演示) +python -m hy3research --mock "测试主题" + +# 仅生成研究计划 +python -m hy3research --plan-only "主题" + +# 指定输出目录 +python -m hy3research --output ./my-research "主题" + +# 完成后自动启动 Web 服务 +python -m hy3research --auto --serve "主题" +``` + +### 3. 查看报告 + +```bash +# 启动 Web 服务 +python -m hy3research serve outputs/<报告目录>/ + +# 或直接浏览器打开 +open outputs/<报告目录>/report.html +``` + +--- + +## 🎬 两个端到端 Demo 流程 + +> 录制脚本见 `demo/record.sh`。 + +**Demo 1 — 浅度研究 (预计 60-90s)** + +``` +$ python -m hy3research --auto "Kubernetes vs Serverless 2026年企业选型对比" +→ Plan: 3 subtopics (成本对比、性能对比、生态对比) +→ Search: ~20 sources → Fetch: ~10 URLs +→ Synthesize: 3 concurrent Hy3 calls +→ Report: 完整 Markdown + Web 页面 +``` + +**Demo 2 — 深度研究 (预计 90-120s)** + +``` +$ python -m hy3research --auto "Transformer架构的替代方案最新进展" +→ Plan: 5 subtopics (Mamba、RWKV、RetNet、线性注意力、混合架构) +→ Search: ~30 sources → Fetch: ~15 URLs +→ Synthesize: 5 concurrent Hy3 calls +→ Report: 深度综述 + 引用索引 + Web 页面 +``` + +--- + +## 🤝 与 CodeBuddy / WorkBuddy 的协作记录 + +本仓库为「vibe-coded」作品,下列模块由 **CodeBuddy / WorkBuddy(基于 Hy3)** 协助生成或重构: + +- `hy3research/client.py`:Hy3 OpenAI 兼容客户端、重试逻辑与 mock 模式(由 CodeBuddy 生成骨架,WorkBuddy 补充推理模型兼容处理)。 +- `hy3research/planner.py`:研究计划生成、JSON 解析与容错(由 WorkBuddy 设计 prompt 结构)。 +- `hy3research/searcher.py`:Tavily + DDG 双引擎搜索与并行调度(复用 issue3 已验证逻辑,WorkBuddy 适配)。 +- `hy3research/reporter.py`:长文报告生成 prompt 设计与输出保存(由 WorkBuddy 撰写)。 +- `hy3research/__main__.py`:CLI 编排逻辑与交互流程(由 WorkBuddy 搭建骨架)。 +- `templates/report.html`:Web 报告模板(由 WorkBuddy 设计并实现暗色/亮色主题)。 +- `README.md` 与 `demo/` 目录:由 WorkBuddy 撰写。 + +其余配置、测试与调试由作者完成。 + +--- + +## 📦 项目结构 + +``` +hy3-research/ +├── hy3research/ +│ ├── __init__.py # 版本信息 +│ ├── __main__.py # CLI 入口 (argparse) +│ ├── config.py # 配置 / .env 加载 +│ ├── client.py # Hy3 客户端 (OpenAI 兼容 + mock) +│ ├── planner.py # 研究计划生成 (Hy3) +│ ├── searcher.py # Tavily + DDG 后备搜索 +│ ├── fetcher.py # URL 内容抓取 + 文本提取 +│ ├── synthesizer.py # 源材料 → Hy3 综合 (per subtopic) +│ ├── reporter.py # 长文报告 + 引用生成 (Hy3) +│ ├── server.py # HTTP 静态文件服务 +│ └── ui.py # 终端渲染 +├── templates/ +│ └── report.html # 报告 Web 模板 (marked.js CDN) +├── tests/ # 单元测试 +├── demo/ # 演示录制脚本 +├── outputs/ # 默认报告输出目录 +├── .env.example +└── README.md +``` + +--- + +## 🔒 安全说明 + +- API Key 仅通过环境变量 / `.env` 提供,且 `.env` 已被 git 忽略,不会入库。 +- 仅在用户确认后执行网络搜索和内容抓取(交互模式)。 +- Mock 模式不发起任何网络请求。 + +--- + +## 📄 License + +MIT — 详见 [LICENSE](../LICENSE)。 + +--- + +## 🐦 提交说明(rhinobird2026) + +本应用在 `issue4/` 目录开发,向 `Tencent-Hunyuan/Hy3` 的 `rhinobird2026` 分支提交 PR。 +PR 附有:项目说明(即本 README)+ 两个 demo 的视频/GIF。 diff --git a/issue4/hy3research/__init__.py b/issue4/hy3research/__init__.py new file mode 100644 index 00000000..d4fec4ff --- /dev/null +++ b/issue4/hy3research/__init__.py @@ -0,0 +1,3 @@ +"""hy3-research: Deep research assistant powered by Hy3.""" + +__version__ = "0.1.0" diff --git a/issue4/hy3research/__main__.py b/issue4/hy3research/__main__.py new file mode 100644 index 00000000..421929a4 --- /dev/null +++ b/issue4/hy3research/__main__.py @@ -0,0 +1,242 @@ +"""CLI entry point for hy3-research: deep research assistant.""" + +from __future__ import annotations + +import argparse +import re +import sys +import time +from datetime import datetime +from pathlib import Path + +from hy3research import __version__ +from hy3research.client import get_client +from hy3research.config import Config +from hy3research.planner import generate_plan +from hy3research.searcher import search_all +from hy3research.fetcher import fetch_all +from hy3research.synthesizer import synthesize_all +from hy3research.reporter import generate_report, save_report +from hy3research.ui import ( + print_header, + print_stage, + print_plan, + print_sources, + print_synthesis_summary, + print_report_summary, + confirm, + _c, + BOLD, + GREEN, + RED, + BLUE, + DIM, + RESET, +) +from hy3research.server import serve_report + + +def _slugify(text: str) -> str: + """Convert text to filesystem-safe slug.""" + slug = re.sub(r'[^\w\s-]', '', text.lower()) + slug = re.sub(r'[-\s]+', '-', slug) + return slug[:50] + + +def _output_dir(topic: str, base: str | None = None) -> str: + """Generate output directory path.""" + root = Path(base) if base else Path("outputs") + timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") + slug = _slugify(topic) + return str(root / f"{slug}-{timestamp}") + + +def cmd_research(args: argparse.Namespace) -> None: + """Run the research pipeline.""" + topic = args.topic + auto = args.auto + mock = args.mock + + print_header(f"🔬 hy3-research v{__version__}") + print(f" 主题: {_c(BOLD, topic)}") + print(f" 模式: {'自动' if auto else '交互'}{' (mock)' if mock else ''}") + print() + + # Verify client works + if not mock and Config.is_mock: + print(_c("", "⚠️ 未配置 HY3_API_KEY,自动切换到 mock 模式\n")) + mock = True + + # ── Stage 1: Plan ── + print_stage("阶段 1/5: 生成研究计划") + plan = generate_plan(topic, mock=mock) + print_plan(plan) + + if not confirm("计划是否可行?", auto=auto): + print("已取消。") + return + + if not auto: + print("可编辑计划(直接回车跳过):") + try: + new_title = input(f" 标题 [{plan['title']}]: ").strip() + if new_title: + plan["title"] = new_title + except (KeyboardInterrupt, EOFError): + return + + # ── Stage 2: Search ── + print_stage("阶段 2/5: 并行搜索") + sources = search_all(plan["subtopics"], mock=mock) + print_sources(sources) + + if not sources: + print(_c(RED, "❌ 搜索无结果。请检查网络或搜索配置。")) + return + + if confirm("是否继续抓取内容?", auto=auto): + # ── Stage 3: Fetch ── + print_stage("阶段 3/5: 抓取源内容") + fetched = fetch_all(sources, mock=mock) + else: + print("已取消抓取。使用已有摘要信息进行综合...") + fetched = [] # skip fetch, proceed with snippets only + ok_count = sum(1 for f in fetched if f["fetch_status"] == "ok") + failed_count = sum(1 for f in fetched if f["fetch_status"] == "failed") + print(f" 抓取结果: {_c(GREEN, str(ok_count) + ' 成功')}, {_c(RED, str(failed_count) + ' 失败')}") + print_sources(fetched) + + # ── Stage 4: Synthesize ── + print_stage("阶段 4/5: 综合材料 (Hy3)") + syntheses = synthesize_all(plan["subtopics"], sources, fetched, mock=mock) + print_synthesis_summary(syntheses) + + if not confirm("是否生成最终报告?", auto=auto): + print("已取消。综合材料已保留在内存中。") + return + + # ── Stage 5: Report ── + print_stage("阶段 5/5: 生成报告 (Hy3)") + report_md = generate_report( + plan["title"], + plan["report_outline"], + syntheses, + sources, + mock=mock, + ) + + output_dir = _output_dir(topic, args.output) + save_report(report_md, output_dir, plan["title"], plan, sources) + print_report_summary(output_dir, plan["title"]) + + # Auto-serve if --serve flag + if args.serve: + port = Config.HY3_RESEARCH_PORT + print(f"\n启动Web服务...") + serve_report(output_dir, port=port) + + +def cmd_serve(args: argparse.Namespace) -> None: + """Serve an existing report directory.""" + port = args.port or Config.HY3_RESEARCH_PORT + serve_report(args.directory, port=port) + + +def cmd_plan(args: argparse.Namespace) -> None: + """Only generate and display research plan.""" + topic = args.topic + mock = args.mock + if not mock and Config.is_mock: + mock = True + print(_c("", "⚠️ 未配置 HY3_API_KEY,自动切换到 mock 模式\n")) + print_header(f"🔬 hy3-research v{__version__} — 仅规划模式") + plan = generate_plan(topic, mock=mock) + print_plan(plan) + + +def _build_research_parser() -> argparse.ArgumentParser: + """Build parser for the default research command (no subcommands).""" + parser = argparse.ArgumentParser( + prog="hy3research", + description="hy3-research: 基于 Hy3 的深度研究助手", + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument( + "--version", action="version", version=f"hy3-research {__version__}" + ) + parser.add_argument("topic", help="研究主题") + parser.add_argument("--auto", action="store_true", help="自动模式,无需交互确认") + parser.add_argument("--mock", action="store_true", help="Mock 离线演示模式") + parser.add_argument("--output", "-o", help="输出目录") + parser.add_argument("--serve", "-s", action="store_true", help="完成后自动启动Web服务") + parser.add_argument("--plan-only", action="store_true", help="仅生成并显示研究计划") + return parser + + +def _build_main_parser() -> argparse.ArgumentParser: + """Build parser with subcommands for serve/plan routing and help display.""" + parser = argparse.ArgumentParser( + prog="hy3research", + description="hy3-research: 基于 Hy3 的深度研究助手", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +示例: + hy3research "量子计算在药物研发中的应用" # 交互模式 + hy3research --auto "AI芯片发展趋势" # 自动模式 + hy3research --mock "测试主题" # Mock 离线演示 + hy3research --plan-only "主题" # 仅规划 + hy3research serve outputs/report/ # 启动Web服务 + hy3research serve outputs/report/ --port 8080 # 自定义端口 + """, + ) + parser.add_argument( + "--version", action="version", version=f"hy3-research {__version__}" + ) + subparsers = parser.add_subparsers(dest="command") + serve_parser = subparsers.add_parser("serve", help="启动Web报告服务") + serve_parser.add_argument("directory", help="报告目录路径") + serve_parser.add_argument("--port", type=int, help="服务端口 (默认 8899)") + serve_parser.set_defaults(func=cmd_serve) + plan_parser = subparsers.add_parser("plan", help="仅生成研究计划") + plan_parser.add_argument("topic", help="研究主题") + plan_parser.add_argument("--mock", action="store_true", help="使用 mock 模式") + plan_parser.set_defaults(func=cmd_plan) + return parser + + +def main() -> None: + """Main CLI entry point.""" + if len(sys.argv) == 1: + _build_main_parser().print_help() + return + + # Detect if first positional arg is a known subcommand + first_pos = None + for arg in sys.argv[1:]: + if not arg.startswith("-"): + first_pos = arg + break + + if first_pos == "serve": + parser = _build_main_parser() + args = parser.parse_args() + cmd_serve(args) + elif first_pos == "plan": + parser = _build_main_parser() + args = parser.parse_args() + cmd_plan(args) + else: + # Default: research command + parser = _build_research_parser() + args = parser.parse_args() + + if args.plan_only: + cmd_plan(args) + elif args.topic: + cmd_research(args) + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/issue4/hy3research/client.py b/issue4/hy3research/client.py new file mode 100644 index 00000000..6bfcc5d3 --- /dev/null +++ b/issue4/hy3research/client.py @@ -0,0 +1,156 @@ +"""Hy3 OpenAI-compatible client with retry and mock mode.""" + +from __future__ import annotations + +import json +import time +from typing import Any + +from hy3research.config import Config + + +class MockClient: + """Returns plausible synthetic responses for offline demo mode.""" + + def _plan_response(self, topic: str) -> str: + return json.dumps({ + "title": f"深度研究报告: {topic}", + "subtopics": [ + {"query": f"{topic} 现状与发展", "key_question": f"{topic}目前的发展状况如何?"}, + {"query": f"{topic} 技术原理", "key_question": f"{topic}的核心技术原理是什么?"}, + {"query": f"{topic} 应用案例", "key_question": f"{topic}有哪些典型应用案例?"}, + {"query": f"{topic} 未来趋势", "key_question": f"{topic}的未来发展趋势是什么?"}, + ], + "report_outline": [ + "1. 引言", + "2. 发展现状", + "3. 核心技术原理", + "4. 典型应用案例", + "5. 未来发展趋势", + "6. 结论", + ], + }, ensure_ascii=False) + + def _synthesize_response(self, key_question: str) -> str: + return ( + f"## 综合回答\n\n" + f"关于「{key_question}」,基于已有材料综合分析如下:\n\n" + f"根据多项研究来源的证据[1][2],该领域在近年取得了显著进展。" + f"核心发现包括技术路线的多元化发展和应用场景的持续扩展[3]。\n\n" + f"**关键要点:**\n\n" + f"- 第一点:技术成熟度不断提升,多个指标达到实用水平\n" + f"- 第二点:产业界投入持续增加,形成良性循环\n" + f"- 第三点:仍存在关键挑战需要突破\n\n" + f"*引用来源: [1] Source A, [2] Source B, [3] Source C*" + ) + + def _report_response(self, topic: str, outline: list[str] | None = None) -> str: + if outline is None: + outline = ["1. 引言", "2. 发展现状", "3. 核心技术", "4. 应用案例", "5. 结论"] + sections = "\n\n".join( + f"## {o.split('. ', 1)[-1] if '. ' in o else o}\n\n" + f"这是关于{o.split('. ', 1)[-1] if '. ' in o else o}的深入分析内容。" + f"基于对多个来源的综合研究,我们在此部分详细探讨了相关要点和发现。" + for o in outline + ) + return ( + f"# {topic}\n\n" + f"## 摘要\n\n" + f"本报告深入研究了「{topic}」,通过系统化的信息收集和分析," + f"从多个维度呈现了该主题的全貌。研究发现,该领域正处于快速发展阶段," + f"值得持续关注和深入研究。\n\n" + f"{sections}\n\n" + f"## 结论\n\n" + f"综合以上分析,「{topic}」是一个具有重要研究价值和实践意义的领域。" + f"建议持续跟踪最新进展,并结合具体应用场景进行深化研究。\n\n" + f"---\n\n" + f"## 参考文献\n\n" + f"[1] Example Source A. https://example.com/a\n\n" + f"[2] Example Source B. https://example.com/b\n\n" + f"[3] Example Source C. https://example.com/c\n" + ) + + def chat(self, messages: list[dict], **kwargs: Any) -> str: + """Return mock response based on system prompt content.""" + system = "" + user = "" + for m in messages: + if m["role"] == "system": + system += m.get("content", "") + elif m["role"] == "user": + user += m.get("content", "") + + if "研究计划" in system or "plan" in system.lower(): + # Extract just the topic from instructions like "请为以下主题生成研究计划:XXX" + topic = user.strip() or "指定主题" + for prefix in ("请为以下主题生成研究计划:", "请为以下主题生成研究计划:"): + if prefix in topic: + topic = topic.split(prefix, 1)[1].strip() + break + return self._plan_response(topic) + elif "综合" in system or "synthesize" in system.lower(): + return self._synthesize_response(user[:100]) + else: + topic = user.strip() or "指定主题" + return self._report_response(topic) + + +class RealClient: + """Hy3 API client with retry logic.""" + + def __init__(self, api_key: str, base_url: str, max_retries: int = 3): + from openai import OpenAI + self._client = OpenAI(api_key=api_key, base_url=base_url) + self._max_retries = max_retries + self._model = Config.HY3_MODEL + + def chat(self, messages: list[dict], max_tokens: int = 0, **kwargs: Any) -> str: + tokens = max_tokens or Config.HY3_MAX_TOKENS + last_error = None + for attempt in range(self._max_retries): + try: + response = self._client.chat.completions.create( + model=self._model, + messages=messages, + max_tokens=tokens, + temperature=kwargs.get("temperature", 0.3), + ) + content = response.choices[0].message.content + if content and len(content.strip()) > 0: + return content.strip() + # Empty content — might be reasoning model, check reasoning_content + if hasattr(response.choices[0].message, "reasoning_content"): + rc = response.choices[0].message.reasoning_content + if rc: + return str(rc).strip() + last_error = Exception("Hy3 returned empty response") + if attempt < self._max_retries - 1: + time.sleep(2 ** attempt) + except Exception as e: + last_error = e + if attempt < self._max_retries - 1: + time.sleep(2 ** attempt) # 1s, 2s, 4s + raise RuntimeError( + f"Hy3 API call failed after {self._max_retries} attempts: {last_error}" + ) + + +def get_client(mock: bool = False) -> MockClient | RealClient: + """Factory: return MockClient or RealClient based on config/mode.""" + if mock or Config.is_mock: + return MockClient() + return RealClient( + api_key=Config.HY3_API_KEY, + base_url=Config.HY3_BASE_URL, + ) + + +def call_hy3( + messages: list[dict], + max_tokens: int = 0, + temperature: float = 0.3, + mock: bool = False, +) -> str: + """Convenience: get client and call chat. Returns response text.""" + client = get_client(mock=mock) + return client.chat(messages, max_tokens=max_tokens, temperature=temperature) diff --git a/issue4/hy3research/config.py b/issue4/hy3research/config.py new file mode 100644 index 00000000..331c95ef --- /dev/null +++ b/issue4/hy3research/config.py @@ -0,0 +1,91 @@ +"""Configuration loader: reads .env from project root or cwd, falls back to env vars.""" + +from __future__ import annotations + +import os +from pathlib import Path + + +def _find_dotenv() -> Path | None: + """Search for .env file: project root first, then cwd, then parent dirs.""" + candidates = [ + Path(__file__).resolve().parent.parent / ".env", # project root + Path.cwd() / ".env", + ] + # also search up from cwd + p = Path.cwd() + while p != p.parent: + candidates.append(p / ".env") + p = p.parent + for path in candidates: + if path.is_file(): + return path + return None + + +def _load_dotenv() -> None: + """Load .env file into os.environ (does not override existing vars).""" + env_path = _find_dotenv() + if env_path is None: + return + try: + text = env_path.read_text(encoding="utf-8-sig") + except OSError: + return + for line in text.splitlines(): + line = line.strip() + if not line or line.startswith("#") or "=" not in line: + continue + name, _, val = line.partition("=") + name = name.strip() + val = val.strip().strip('"').strip("'") + if name and name not in os.environ: + os.environ[name] = val + + +class _Config: + """Namespace for configuration values, loaded from env with defaults.""" + + def _get(self, key: str, default: str = "") -> str: + return os.environ.get(key, default).strip() + + @property + def HY3_API_KEY(self) -> str: + return self._get("HY3_API_KEY") + + @property + def HY3_BASE_URL(self) -> str: + return self._get("HY3_BASE_URL", "https://api.hunyuan.cloud.tencent.com/v1") + + @property + def HY3_MODEL(self) -> str: + return self._get("HY3_MODEL", "hunyuan-3.0-free") + + @property + def HY3_MAX_TOKENS(self) -> int: + val = self._get("HY3_MAX_TOKENS", "16384") + try: + return int(val) + except ValueError: + return 16384 + + @property + def TAVILY_API_KEY(self) -> str: + return self._get("TAVILY_API_KEY") + + @property + def HY3_RESEARCH_PORT(self) -> int: + val = self._get("HY3_RESEARCH_PORT", "8899") + try: + return int(val) + except ValueError: + return 8899 + + @property + def is_mock(self) -> bool: + return not self.HY3_API_KEY + + +# Load on import +_load_dotenv() +Config = _Config() diff --git a/issue4/hy3research/fetcher.py b/issue4/hy3research/fetcher.py new file mode 100644 index 00000000..57fec076 --- /dev/null +++ b/issue4/hy3research/fetcher.py @@ -0,0 +1,178 @@ +"""Content fetcher: URL → HTML → plain text extraction.""" + +from __future__ import annotations + +import concurrent.futures +import re +import time +import requests + + +USER_AGENT = "Mozilla/5.0 (compatible; hy3-research/0.1; +https://github.com/Tencent-Hunyuan/Hy3)" +FETCH_TIMEOUT = 30 # seconds + +# File extensions to skip (non-HTML content) +SKIP_EXTENSIONS = {".pdf", ".mp4", ".avi", ".mov", ".zip", ".tar", ".gz", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".mp3", ".wav"} + + +def extract_text(html: str) -> str: + """Extract readable text from HTML using BeautifulSoup. + + Removes script, style, nav, footer elements. Returns cleaned text. + """ + try: + from bs4 import BeautifulSoup + except ImportError: + # Minimal fallback: strip tags with regex + text = re.sub(r']*>.*?', '', html, flags=re.DOTALL | re.IGNORECASE) + text = re.sub(r']*>.*?', '', text, flags=re.DOTALL | re.IGNORECASE) + text = re.sub(r'<[^>]+>', '', text) + text = re.sub(r'\s+', ' ', text) + return text.strip() + + soup = BeautifulSoup(html, "html.parser") + + # Remove non-content elements + for tag in soup.find_all(["script", "style", "nav", "footer", "header", "aside"]): + tag.decompose() + + # Get text from body, or whole document + body = soup.find("body") + target = body if body else soup + text = target.get_text(separator=" ", strip=True) + + # Normalize whitespace + text = re.sub(r'\s+', ' ', text) + return text.strip() + + +def _should_skip(url: str) -> bool: + """Check if URL should be skipped (PDF, video, etc.).""" + from urllib.parse import urlsplit + import os.path + path = urlsplit(url).path + if not path: + return False + ext = os.path.splitext(path)[1].lower() + return ext in SKIP_EXTENSIONS + + +def fetch_single(url: str, timeout: int = FETCH_TIMEOUT) -> dict: + """Fetch a single URL and extract text. + + Returns: + {url, raw_text, fetch_status, fetch_time} + """ + start = time.time() + if _should_skip(url): + return { + "url": url, + "raw_text": "", + "fetch_status": "skipped", + "fetch_time": 0, + } + + try: + resp = requests.get( + url, + timeout=timeout, + headers={"User-Agent": USER_AGENT}, + allow_redirects=True, + ) + resp.raise_for_status() + # Only process HTML responses + content_type = resp.headers.get("Content-Type", "") + if "html" not in content_type.lower() and "text" not in content_type.lower(): + return { + "url": url, + "raw_text": "", + "fetch_status": "skipped", + "fetch_time": time.time() - start, + } + raw_text = extract_text(resp.text) + elapsed = time.time() - start + return { + "url": url, + "raw_text": raw_text, + "fetch_status": "ok", + "fetch_time": round(elapsed, 2), + } + except Exception: + elapsed = time.time() - start + return { + "url": url, + "raw_text": "", + "fetch_status": "failed", + "fetch_time": round(elapsed, 2), + } + + +def fetch_all(sources: list[dict], mock: bool = False) -> list[dict]: + """Fetch all source URLs in parallel and extract text. + + Args: + sources: List of {url, title, index, ...} from searcher. + mock: If True, return synthetic content. + + Returns: + List of {url, title, raw_text, fetch_status, fetch_time, index}. + """ + if mock: + return _mock_fetch(sources) + + # Build lookup for titles + title_map = {s["url"]: s.get("title", "") for s in sources} + + results = [] + urls = [s["url"] for s in sources] + + with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: + futures = {executor.submit(fetch_single, url): url for url in urls} + for future in concurrent.futures.as_completed(futures): + url = futures[future] + try: + result = future.result() + except Exception: + result = { + "url": url, + "raw_text": "", + "fetch_status": "failed", + "fetch_time": 0, + } + result["title"] = title_map.get(url, "") + result["index"] = next( + (s["index"] for s in sources if s["url"] == url), 0 + ) + results.append(result) + + # Sort by index to maintain order + results.sort(key=lambda r: r.get("index", 0)) + return results + + +def _mock_fetch(sources: list[dict]) -> list[dict]: + """Generate synthetic fetched content for offline demo.""" + results = [] + for s in sources: + idx = s.get("index", 0) + title = s.get("title", "") + results.append({ + "url": s["url"], + "title": title, + "raw_text": ( + f"这是关于「{s.get('query', '')}」的研究文章《{title}》的正文内容。\n\n" + f"本文详细探讨了该主题的多个方面。首先,从背景来看,该领域近年来吸引了大量关注和研究投入。" + f"多个权威机构和学者都发表了相关研究,推动了理论和实践的同步发展。\n\n" + f"在技术层面,核心创新包括新的方法论和工具链的成熟。与传统方法相比,新技术在效率、准确性和" + f"可扩展性方面都有显著提升。多项基准测试结果证实了这些优势。\n\n" + f"从应用角度,已经有多个实际案例证明了其价值。在工业界,大型科技公司已经开始将其整合到" + f"生产环境中;在学术界,相关论文数量在过去两年增长了200%。\n\n" + f"然而,也存在一些挑战和限制。包括数据质量、计算资源需求、以及在一些边缘场景下的鲁棒性问题。" + f"研究者正在积极应对这些挑战,预计在未来1-2年内会有突破性进展。\n\n" + f"总的来说,该主题代表了当前技术发展的重要方向,值得持续关注和深入研究。" + ), + "fetch_status": "ok", + "fetch_time": 0.0, + "index": idx, + }) + return results diff --git a/issue4/hy3research/planner.py b/issue4/hy3research/planner.py new file mode 100644 index 00000000..cd06be5e --- /dev/null +++ b/issue4/hy3research/planner.py @@ -0,0 +1,81 @@ +"""Research planner: generates structured research plan via Hy3.""" + +from __future__ import annotations + +import json +import re +from hy3research.client import call_hy3 + +PLAN_SYSTEM_PROMPT = """你是一个资深研究规划专家。用户会给你一个研究主题,你需要生成一份结构化的研究计划。 + +要求: +1. 将主题拆分为3-6个子主题 +2. 为每个子主题生成一个搜索query和核心问题 +3. 生成报告大纲(6-10个章节) + +输出格式(严格JSON,不包含markdown代码块标记): +{ + "title": "报告标题", + "subtopics": [ + {"query": "搜索关键词", "key_question": "该子主题要回答的核心问题"} + ], + "report_outline": ["1. 引言", "2. xxx", ...] +} +""" + + +def _extract_json(text: str) -> str: + """Extract JSON from text that may have markdown fences.""" + # Try to find JSON block + match = re.search(r'```(?:json)?\s*\n?(.*?)\n?```', text, re.DOTALL) + if match: + return match.group(1).strip() + # Try to find raw JSON object with balanced braces + start = text.find('{') + if start == -1: + return text.strip() + depth = 0 + for i, ch in enumerate(text[start:], start): + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + if depth == 0: + return text[start:i + 1].strip() + return text.strip() + + +def generate_plan(topic: str, mock: bool = False) -> dict: + """Generate research plan for a topic. + + Args: + topic: Research topic string. + mock: Use mock client if True. + + Returns: + Dict with keys: title, subtopics, report_outline. + """ + messages = [ + {"role": "system", "content": PLAN_SYSTEM_PROMPT}, + {"role": "user", "content": f"请为以下主题生成研究计划:{topic}"}, + ] + response = call_hy3(messages, max_tokens=4096, temperature=0.3, mock=mock) + json_str = _extract_json(response) + try: + plan = json.loads(json_str) + except json.JSONDecodeError: + # Fallback: return minimal valid plan + plan = { + "title": topic, + "subtopics": [{"query": topic, "key_question": f"{topic}的核心问题是什么?"}], + "report_outline": ["1. 引言", "2. 主体分析", "3. 结论"], + } + # Validate required fields and types + plan.setdefault("title", topic) + if not isinstance(plan.get("subtopics"), list): + plan["subtopics"] = [{"query": topic, "key_question": f"{topic}的核心问题是什么?"}] + plan.setdefault("subtopics", [{"query": topic, "key_question": topic}]) + if not isinstance(plan.get("report_outline"), list): + plan["report_outline"] = ["1. 引言", "2. 分析", "3. 结论"] + plan.setdefault("report_outline", ["1. 引言", "2. 分析", "3. 结论"]) + return plan diff --git a/issue4/hy3research/reporter.py b/issue4/hy3research/reporter.py new file mode 100644 index 00000000..7ef744f5 --- /dev/null +++ b/issue4/hy3research/reporter.py @@ -0,0 +1,130 @@ +"""Reporter: final long-form report generation via Hy3.""" + +from __future__ import annotations + +from hy3research.client import call_hy3 + +REPORT_SYSTEM_PROMPT = """你是一个资深研究报告撰写专家。用户会提供: +1. 报告主题和标题 +2. 报告大纲 +3. 每个章节的综合分析材料(含引用标注 [1][2]...) +4. 引用来源列表 + +请基于以上材料,撰写一份完整、结构化的深度研究报告。要求: +- 使用Markdown格式 +- 包含摘要、各章节正文、结论 +- 保留所有引用标注 [1][2] +- 文末包含完整的参考文献列表(统一编号) +- 语言专业、客观、准确 +- 总字数不少于2000字 + +直接输出Markdown报告全文,不需要包裹在JSON中。""" + + +def generate_report( + title: str, + outline: list[str], + syntheses: list[dict], + sources: list[dict], + mock: bool = False, +) -> str: + """Generate final research report. + + Args: + title: Report title. + outline: Report chapter outline from planner. + syntheses: List of {subtopic, synthesized_text, cited_sources} from synthesizer. + sources: All source metadata with indices. + mock: Use mock client. + + Returns: + Complete Markdown report string. + """ + # Build synthesis context + synthesis_text = "\n\n".join( + f"### {s['subtopic']['query']}\n{s['synthesized_text']}" + for s in syntheses + ) + + # Build reference list + ref_lines = [] + for s in sorted(sources, key=lambda x: x.get("index", 0)): + idx = s.get("index", 0) + url = s.get("url", "") + title = s.get("title", "") + ref_lines.append(f"[{idx}] **{title}**\n {url}") + + ref_text = "\n\n".join(ref_lines) if ref_lines else "暂无引用来源" + + outline_text = "\n".join(outline) + + user_prompt = ( + f"报告标题:{title}\n\n" + f"报告大纲:\n{outline_text}\n\n" + f"各章节综合材料:\n{synthesis_text}\n\n" + f"引用来源列表:\n{ref_text}\n\n" + f"请基于以上材料撰写完整的研究报告。" + ) + + messages = [ + {"role": "system", "content": REPORT_SYSTEM_PROMPT}, + {"role": "user", "content": user_prompt}, + ] + + report = call_hy3(messages, max_tokens=16384, temperature=0.3, mock=mock) + + # Ensure report has reference section if missing + if "参考" not in report: + report += "\n\n---\n\n## 参考文献\n\n" + ref_text + + return report + + +def save_report( + report_md: str, + output_dir: str, + title: str, + plan: dict, + sources: list[dict], + report_html: str = "", +) -> str: + """Save report and metadata to output directory. + + Args: + report_md: Markdown report content. + output_dir: Output directory path. + title: Report title. + plan: Research plan dict. + sources: All source metadata. + report_html: Optional HTML report content. + + Returns: + Output directory path. + """ + import os + import json + + os.makedirs(output_dir, exist_ok=True) + + # Save markdown report + md_path = os.path.join(output_dir, "report.md") + with open(md_path, "w", encoding="utf-8") as f: + f.write(report_md) + + # Save sources + sources_path = os.path.join(output_dir, "sources.json") + with open(sources_path, "w", encoding="utf-8") as f: + json.dump(sources, f, ensure_ascii=False, indent=2) + + # Save plan + plan_path = os.path.join(output_dir, "research_plan.json") + with open(plan_path, "w", encoding="utf-8") as f: + json.dump(plan, f, ensure_ascii=False, indent=2) + + # Save HTML if provided + if report_html: + html_path = os.path.join(output_dir, "report.html") + with open(html_path, "w", encoding="utf-8") as f: + f.write(report_html) + + return output_dir diff --git a/issue4/hy3research/searcher.py b/issue4/hy3research/searcher.py new file mode 100644 index 00000000..47b6eef7 --- /dev/null +++ b/issue4/hy3research/searcher.py @@ -0,0 +1,128 @@ +"""Search module: Tavily + DDG fallback, parallel search execution.""" + +from __future__ import annotations + +import concurrent.futures +from hy3research.config import Config + + +def search_single(query: str, max_results: int = 10) -> list[dict]: + """Search with Tavily, fallback to DDG. Returns [{title, url, snippet}].""" + results = _search_tavily(query, max_results) + if results is None or len(results) == 0: + results = _search_ddg(query, max_results) + return results + + +def _search_tavily(query: str, max_results: int) -> list[dict] | None: + """Tavily search, returns None on failure.""" + api_key = Config.TAVILY_API_KEY + if not api_key: + return None + try: + from tavily import TavilyClient + client = TavilyClient(api_key=api_key) + response = client.search(query=query, max_results=max_results, search_depth="basic") + items = response.get("results", []) + return [ + { + "title": r.get("title", ""), + "url": r.get("url", ""), + "snippet": (r.get("content", "") or "")[:300], + } + for r in items[:max_results] + ] + except Exception: + return None + + +def _search_ddg(query: str, max_results: int) -> list[dict]: + """DuckDuckGo search fallback. Returns empty list on failure.""" + try: + from ddgs import DDGS + results = [] + with DDGS() as ddgs: + for r in ddgs.text(query, max_results=max_results): + results.append({ + "title": r.get("title", ""), + "url": r.get("href", ""), + "snippet": (r.get("body", "") or "")[:300], + }) + return results + except Exception: + return [] + + +def deduplicate_sources(sources: list[dict]) -> list[dict]: + """Remove duplicate URLs, keeping first occurrence.""" + seen = set() + unique = [] + for s in sources: + if s["url"] not in seen: + seen.add(s["url"]) + unique.append(s) + return unique + + +def search_all(subtopics: list[dict], mock: bool = False) -> list[dict]: + """Run parallel search for all subtopic queries, deduplicate results. + + Args: + subtopics: List of {query, key_question} dicts from planner. + mock: If True, return synthetic results without network calls. + + Returns: + List of {index, url, title, snippet, query} with global dedup. + """ + if mock: + all_sources = _mock_search(subtopics) + else: + all_sources = [] + with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor: + futures = { + executor.submit(search_single, st.get("query", ""), 10): st + for st in subtopics + } + for future in concurrent.futures.as_completed(futures): + st = futures[future] + try: + results = future.result() + except Exception: + results = [] + for r in results: + r = dict(r, query=st.get("query", "")) + all_sources.append(r) + + unique = deduplicate_sources(all_sources) + # Cap at 40 sources + unique = unique[:40] + # Add global index + for i, s in enumerate(unique): + s["index"] = i + 1 + return unique + + +def _mock_search(subtopics: list[dict]) -> list[dict]: + """Generate synthetic search results for offline demo.""" + mock_data = [] + idx = 0 + domains = [ + ("techcrunch.com", "TechCrunch"), + ("arxiv.org", "arXiv"), + ("wikipedia.org", "Wikipedia"), + ("github.com", "GitHub"), + ("medium.com", "Medium"), + ("nature.com", "Nature"), + ] + for st in subtopics: + query = st["query"] + for j, (domain, site_name) in enumerate(domains[:3]): + idx += 1 + mock_data.append({ + "url": f"https://{domain}/article-about-{query.replace(' ', '-')[:30]}-{j}", + "title": f"[Mock] {query} — {site_name} 深度分析", + "snippet": f"关于「{query}」的综合分析文章,涵盖了最新进展、核心概念和实践案例。" + f"这篇文章提供了该领域的全面概述,适合研究参考。", + "query": query, + }) + return mock_data diff --git a/issue4/hy3research/server.py b/issue4/hy3research/server.py new file mode 100644 index 00000000..fb3ef753 --- /dev/null +++ b/issue4/hy3research/server.py @@ -0,0 +1,83 @@ +"""HTTP static file server for viewing research reports in browser.""" + +from __future__ import annotations + +import http.server +import os +import socket +import webbrowser +from pathlib import Path +from hy3research.ui import print_header, _c, BOLD, GREEN, CYAN, RESET + + +TEMPLATE_DIR = Path(__file__).resolve().parent.parent / "templates" + + +def serve_report(report_dir: str, port: int = 8899, open_browser: bool = True) -> None: + """Serve a report directory over HTTP and optionally open browser. + + Args: + report_dir: Path to directory containing report.md and report.html. + port: Port to listen on. + open_browser: Whether to auto-open browser. + """ + report_path = Path(report_dir).resolve() + + if not report_path.is_dir(): + print(f"错误: 目录不存在 — {report_path}") + return + + report_md = report_path / "report.md" + if not report_md.is_file(): + print(f"警告: 未找到 report.md — {report_md}") + + # If report.html or index.html doesn't exist, generate from template + report_html = report_path / "report.html" + index_html = report_path / "index.html" + if not report_html.is_file() or not index_html.is_file(): + _generate_html(report_path) + + os.chdir(str(report_path)) + + handler = http.server.SimpleHTTPRequestHandler + + print_header(f"🌐 hy3-research 报告服务") + print(f" 目录: {report_path}") + print(f" 地址: {_c(BOLD + GREEN, f'http://localhost:{port}')}") + print(f" 按 {_c(BOLD, 'Ctrl+C')} 停止服务") + print() + + if open_browser: + webbrowser.open(f"http://localhost:{port}") + + try: + with http.server.HTTPServer(("", port), handler) as httpd: + httpd.serve_forever() + except socket.error as e: + # Port already in use + print(f"{_c('', '端口 {port} 被占用')}: {e}") + except KeyboardInterrupt: + print(f"\n{_c(BOLD + GREEN, '✓')} 服务已停止") + + +def _generate_html(report_dir: Path) -> None: + """Generate report.html from template with embedded markdown content.""" + template_path = TEMPLATE_DIR / "report.html" + report_md = report_dir / "report.md" + + if not template_path.is_file(): + print(f"警告: 模板文件不存在 — {template_path}") + return + + template = template_path.read_text(encoding="utf-8") + + if report_md.is_file(): + md_content = report_md.read_text(encoding="utf-8") + # Escape for JS string + md_escaped = md_content.replace("\\", "\\\\").replace("`", "\\`").replace("$", "\\$") + html = template.replace("__REPORT_MARKDOWN__", md_escaped).replace("__REPORT_TITLE__", report_dir.name) + else: + html = template.replace("__REPORT_MARKDOWN__", "# 报告未找到").replace("__REPORT_TITLE__", report_dir.name) + + (report_dir / "report.html").write_text(html, encoding="utf-8") + (report_dir / "index.html").write_text(html, encoding="utf-8") # Also serve as default page diff --git a/issue4/hy3research/synthesizer.py b/issue4/hy3research/synthesizer.py new file mode 100644 index 00000000..a4f92f25 --- /dev/null +++ b/issue4/hy3research/synthesizer.py @@ -0,0 +1,142 @@ +"""Synthesizer: per-subtopic source merging and synthesis via Hy3.""" + +from __future__ import annotations + +import concurrent.futures +from hy3research.client import call_hy3 + +SYNTHESIZE_SYSTEM_PROMPT = """你是一个研究分析专家。用户会提供: +1. 一个子主题的核心问题 +2. 一组相关的源材料(编号[1][2]...,包含标题和正文) + +请基于这些源材料,用中文综合回答该核心问题。要求: +- 保留引用标注,使用 [1][2] 格式标注信息来源 +- 客观、准确,不要添加材料中没有的信息 +- 如果材料之间存在矛盾,请指出 +- 结构化回答(可用小标题) + +只需要输出综合后的回答文本,不需要JSON格式。""" + + +def synthesize_subtopic( + subtopic: dict, + sources: list[dict], + fetched: list[dict], + mock: bool = False, +) -> dict: + """Synthesize materials for a single subtopic. + + Args: + subtopic: {query, key_question} from planner. + sources: All source metadata with indices. + fetched: Fetched content with raw_text. + mock: Use mock client. + + Returns: + {subtopic, synthesized_text, cited_sources: [int]}. + """ + # Find which sources are relevant to this subtopic's query + query = subtopic["query"] + query_lower = query.lower() + + # Match fetched content to sources by URL + relevant_sources = [] + for s in sources: + # Check if this source belongs to this query + if s.get("query", "").lower() == query_lower or query_lower in s.get("query", "").lower(): + relevant_sources.append(s) + + if not relevant_sources: + # If no exact match, use all sources + relevant_sources = sources + + # Build context from fetched content + context_parts = [] + cited_indices = [] + for s in relevant_sources: + idx = s.get("index", 0) + title = s.get("title", "") + # Find matching fetched content + matched = next( + (f for f in fetched if f.get("index") == idx and f.get("fetch_status") == "ok"), + None, + ) + if matched and matched.get("raw_text"): + text = matched["raw_text"][:2000] # Truncate per source + context_parts.append(f"[{idx}] {title}\n{text}") + cited_indices.append(idx) + + if not context_parts: + return { + "subtopic": subtopic, + "synthesized_text": f"## {query}\n\n该子主题暂无足够的源材料可供综合。", + "cited_sources": [], + } + + context = "\n\n---\n\n".join(context_parts) + user_prompt = ( + f"核心问题:{subtopic['key_question']}\n\n" + f"源材料:\n{context}\n\n" + f"请基于以上源材料,综合回答核心问题。保留引用标注。" + ) + + messages = [ + {"role": "system", "content": SYNTHESIZE_SYSTEM_PROMPT}, + {"role": "user", "content": user_prompt}, + ] + + synthesized_text = call_hy3(messages, max_tokens=4096, temperature=0.3, mock=mock) + + return { + "subtopic": subtopic, + "synthesized_text": synthesized_text, + "cited_sources": cited_indices, + } + + +def synthesize_all( + subtopics: list[dict], + sources: list[dict], + fetched: list[dict], + mock: bool = False, +) -> list[dict]: + """Synthesize all subtopics in parallel. + + Returns: + List of {subtopic, synthesized_text, cited_sources}. + """ + if mock: + return [ + synthesize_subtopic(st, sources, fetched, mock=True) + for st in subtopics + ] + + results = [] + with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor: + futures = { + executor.submit( + synthesize_subtopic, st, sources, fetched, mock + ): st + for st in subtopics + } + for future in concurrent.futures.as_completed(futures): + try: + result = future.result() + results.append(result) + except Exception: + st = futures[future] + results.append({ + "subtopic": st, + "synthesized_text": f"## {st['query']}\n\n综合过程出错,请重试此子主题。", + "cited_sources": [], + }) + + # Sort by original subtopic order + ordered = [] + for st in subtopics: + match = next( + (r for r in results if r["subtopic"]["query"] == st["query"]), None + ) + if match: + ordered.append(match) + return ordered diff --git a/issue4/hy3research/ui.py b/issue4/hy3research/ui.py new file mode 100644 index 00000000..56f57435 --- /dev/null +++ b/issue4/hy3research/ui.py @@ -0,0 +1,124 @@ +"""Terminal UI helpers for hy3-research CLI.""" + +from __future__ import annotations + +import sys + +# ANSI color codes +BOLD = "\033[1m" +DIM = "\033[2m" +GREEN = "\033[32m" +BLUE = "\033[34m" +YELLOW = "\033[33m" +RED = "\033[31m" +CYAN = "\033[36m" +RESET = "\033[0m" + +SEPARATOR = "─" * 60 + + +def supports_color() -> bool: + """Check if terminal supports ANSI colors.""" + if not sys.stdout.isatty(): + return False + if sys.platform == "win32": + try: + import ctypes + kernel32 = ctypes.windll.kernel32 + kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) + return True + except Exception: + return False + return True + + +def _c(code: str, text: str) -> str: + """Apply color code if supported.""" + if supports_color(): + return f"{code}{text}{RESET}" + return text + + +def print_header(text: str) -> None: + """Print main title banner.""" + print() + print(SEPARATOR) + print(_c(BOLD + BLUE, text)) + print(SEPARATOR) + print() + + +def print_stage(text: str) -> None: + """Print stage indicator.""" + print(f"\n{_c(BOLD + CYAN, '▸')} {_c(BOLD, text)}") + print(SEPARATOR) + + +def print_plan(plan: dict) -> None: + """Display research plan to user.""" + print(_c(BOLD, f"\n研究主题: {plan.get('title', 'N/A')}")) + print(_c(DIM, f"\n子主题 ({len(plan.get('subtopics', []))} 个):")) + for i, st in enumerate(plan.get("subtopics", []), 1): + print(f" {i}. {st['query']}") + print(f" {_c(DIM, '核心问题: ' + st['key_question'])}") + print(_c(DIM, f"\n报告大纲:")) + for ol in plan.get("report_outline", []): + print(f" {ol}") + print() + + +def print_sources(sources: list[dict]) -> None: + """Display search results summary.""" + ok_count = sum(1 for s in sources if s.get("fetch_status", "ok") != "failed") + print(_c(BOLD, f"\n来源 ({len(sources)} 条, {ok_count} 条可用):")) + for s in sources[:15]: # Show first 15 + status = _c(GREEN, "✓") if s.get("fetch_status", "ok") != "failed" else _c(RED, "✗") + print(f" [{s.get('index', '?')}] {status} {s.get('title', '')[:70]}") + print(f" {_c(DIM, s.get('url', '')[:80])}") + if len(sources) > 15: + print(f" ... 还有 {len(sources) - 15} 条") + print() + + +def print_synthesis_summary(syntheses: list[dict]) -> None: + """Display synthesis progress summary.""" + print(_c(BOLD, f"\n综合完成 ({len(syntheses)} 个子主题):")) + for s in syntheses: + query = s["subtopic"]["query"] + cited = len(s.get("cited_sources", [])) + text_len = len(s.get("synthesized_text", "")) + print(f" {_c(GREEN, '✓')} {query} — {cited} 引用, {text_len} 字符") + print() + + +def print_report_summary(path: str, title: str) -> None: + """Display report save confirmation.""" + print() + print(SEPARATOR) + print(_c(BOLD + GREEN, "✓ 报告生成完成!")) + print(f" 标题: {title}") + print(f" 路径: {path}") + print(f"\n 查看报告: {_c(BOLD, f'python -m hy3research serve {path}')}") + print(SEPARATOR) + print() + + +def confirm(text: str, auto: bool = False) -> bool: + """Ask user for confirmation. In auto mode, always returns True. + + Args: + text: Confirmation prompt text. + auto: If True, skip interaction and return True. + + Returns: + True if confirmed, False otherwise. + """ + if auto: + print(f"{_c(DIM, '[auto]')} {text} → 是") + return True + try: + answer = input(f"{text} [Y/n]: ").strip().lower() + return answer in ("", "y", "yes") + except (KeyboardInterrupt, EOFError): + print() + return False diff --git a/issue4/outputs/.gitkeep b/issue4/outputs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/issue4/pyproject.toml b/issue4/pyproject.toml new file mode 100644 index 00000000..ba00a405 --- /dev/null +++ b/issue4/pyproject.toml @@ -0,0 +1,19 @@ +[build-system] +requires = ["setuptools>=64"] +build-backend = "setuptools.backends._legacy:_Backend" + +[project] +name = "hy3-research" +version = "0.1.0" +description = "Deep research assistant powered by Hy3" +requires-python = ">=3.8" +dependencies = [ + "openai>=1.0", + "requests>=2.25", + "beautifulsoup4>=4.9", + "tavily-python>=0.3", + "ddgs>=5.0", +] + +[project.scripts] +hy3research = "hy3research.__main__:main" diff --git a/issue4/requirements.txt b/issue4/requirements.txt new file mode 100644 index 00000000..e80cf5c3 --- /dev/null +++ b/issue4/requirements.txt @@ -0,0 +1,6 @@ +openai>=1.0 +requests>=2.25 +beautifulsoup4>=4.9 +tavily-python>=0.3 +ddgs>=5.0 +pytest>=7.0 diff --git a/issue4/templates/report.html b/issue4/templates/report.html new file mode 100644 index 00000000..c5b3f8aa --- /dev/null +++ b/issue4/templates/report.html @@ -0,0 +1,163 @@ + + + + + +__REPORT_TITLE__ — hy3-research + + + + + + + +

+ + + + + diff --git a/issue4/tests/test_client_mock.py b/issue4/tests/test_client_mock.py new file mode 100644 index 00000000..11331fc9 --- /dev/null +++ b/issue4/tests/test_client_mock.py @@ -0,0 +1,33 @@ +"""Tests for hy3research.client mock mode.""" + +import json +import pytest +from hy3research.client import MockClient, get_client + + +class TestMockClient: + def test_mock_returns_json_for_plan_prompt(self): + client = MockClient() + messages = [ + {"role": "system", "content": "输出JSON格式的研究计划"}, + {"role": "user", "content": "test topic"}, + ] + result = client.chat(messages) + assert isinstance(result, str) + # Should be parseable JSON + data = json.loads(result) + assert "title" in data + assert "subtopics" in data + + def test_mock_returns_text_for_general_prompt(self): + client = MockClient() + messages = [ + {"role": "user", "content": "write a report about AI"}, + ] + result = client.chat(messages) + assert isinstance(result, str) + assert len(result) > 50 + + def test_mock_client_not_None(self): + client = get_client(mock=True) + assert isinstance(client, MockClient) diff --git a/issue4/tests/test_fetcher.py b/issue4/tests/test_fetcher.py new file mode 100644 index 00000000..fe7835c4 --- /dev/null +++ b/issue4/tests/test_fetcher.py @@ -0,0 +1,40 @@ +"""Tests for hy3research.fetcher.""" + +import pytest +from hy3research.fetcher import extract_text, fetch_all + + +class TestExtractText: + def test_extracts_text_from_html(self): + html = "

Hello World

More text here.

" + text = extract_text(html) + assert "Hello World" in text + assert "More text" in text + assert "console.log" not in text + + def test_strips_extra_whitespace(self): + html = "

Lots of spaces

" + text = extract_text(html) + assert "Lots of spaces" in text + + +class TestFetchAll: + def test_mock_returns_structured_data(self): + sources = [ + {"url": "https://example.com/a", "title": "Article A", "index": 1, "query": "test"}, + {"url": "https://example.com/b", "title": "Article B", "index": 2, "query": "test2"}, + ] + results = fetch_all(sources, mock=True) + assert len(results) == 2 + for r in results: + assert r["fetch_status"] in ("ok", "failed", "skipped") + assert "raw_text" in r + assert "fetch_time" in r + assert isinstance(r["fetch_time"], (int, float)) + + def test_mock_text_is_substantial(self): + sources = [ + {"url": "https://example.com/a", "title": "Test", "index": 1, "query": "x"}, + ] + results = fetch_all(sources, mock=True) + assert len(results[0]["raw_text"]) > 100 diff --git a/issue4/tests/test_planner.py b/issue4/tests/test_planner.py new file mode 100644 index 00000000..285139ab --- /dev/null +++ b/issue4/tests/test_planner.py @@ -0,0 +1,30 @@ +"""Tests for hy3research.planner.""" + +import pytest +from hy3research.planner import generate_plan, PLAN_SYSTEM_PROMPT + + +class TestPlanner: + def test_mock_plan_has_required_fields(self): + plan = generate_plan("人工智能发展趋势", mock=True) + assert "title" in plan + assert "subtopics" in plan + assert "report_outline" in plan + assert len(plan["subtopics"]) >= 2 + assert len(plan["subtopics"]) <= 6 + for st in plan["subtopics"]: + assert "query" in st + assert "key_question" in st + + def test_mock_plan_title_contains_topic(self): + plan = generate_plan("量子计算", mock=True) + assert "量子计算" in plan["title"] + + def test_mock_plan_outline_not_empty(self): + plan = generate_plan("气候变化", mock=True) + assert len(plan["report_outline"]) >= 3 + + def test_system_prompt_asks_for_json(self): + assert "JSON" in PLAN_SYSTEM_PROMPT + assert "研究计划" in PLAN_SYSTEM_PROMPT + assert "subtopics" in PLAN_SYSTEM_PROMPT diff --git a/issue4/tests/test_searcher.py b/issue4/tests/test_searcher.py new file mode 100644 index 00000000..6853d87e --- /dev/null +++ b/issue4/tests/test_searcher.py @@ -0,0 +1,49 @@ +"""Tests for hy3research.searcher.""" + +import pytest +from hy3research.searcher import deduplicate_sources, search_all + + +class TestDeduplicate: + def test_removes_duplicate_urls(self): + sources = [ + {"url": "http://a.com", "title": "A"}, + {"url": "http://a.com", "title": "A dup"}, + {"url": "http://b.com", "title": "B"}, + ] + result = deduplicate_sources(sources) + urls = [s["url"] for s in result] + assert urls == ["http://a.com", "http://b.com"] + + def test_preserves_first_occurrence(self): + sources = [ + {"url": "http://a.com", "title": "First"}, + {"url": "http://a.com", "title": "Second"}, + ] + result = deduplicate_sources(sources) + assert result[0]["title"] == "First" + + +class TestSearchAll: + def test_returns_list_with_indices(self): + subtopics = [ + {"query": "Python programming", "key_question": "What is Python?"}, + ] + results = search_all(subtopics, mock=True) + assert isinstance(results, list) + assert len(results) > 0 + for r in results: + assert "index" in r + assert "url" in r + assert "title" in r + assert "snippet" in r + assert "query" in r + + def test_mock_no_duplicates(self): + subtopics = [ + {"query": "same query", "key_question": "q1"}, + {"query": "same query", "key_question": "q2"}, + ] + results = search_all(subtopics, mock=True) + urls = [r["url"] for r in results] + assert len(urls) == len(set(urls))