Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/04-开发计划/最小MVP闭环开发计划.md
HaHafeng 1b53ab9d52 feat(aia): Complete AIA V2.0 with universal streaming capabilities
Major Changes:
- Add StreamingService with OpenAI Compatible format
- Upgrade Chat component V2 with Ant Design X integration
- Implement AIA module with 12 intelligent agents
- Update API routes to unified /api/v1 prefix
- Update system documentation

Backend (~1300 lines):
- common/streaming: OpenAI Compatible adapter
- modules/aia: 12 agents, conversation service, streaming integration
- Update route versions (RVW, PKB to v1)

Frontend (~3500 lines):
- modules/aia: AgentHub + ChatWorkspace (100% prototype restoration)
- shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook
- Update API endpoints to v1

Documentation:
- AIA module status guide
- Universal capabilities catalog
- System overview updates
- All module documentation sync

Tested: Stream response verified, authentication working
Status: AIA V2.0 core completed (85%)
2026-01-14 19:15:01 +08:00

1222 lines
46 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# IIT Manager Agent - 譛€蟆舟VP髣ュ邇ッ蠑€蜿題ョ。蛻?
> **迚域悽**: v1.0
> **蛻帛サコ譌・譛<EFBDA5>**: 2026-01-02
> **逶ョ譬<EFBDAE>**: 謇馴€?REDCap 竊?Node.js 竊?莨∽ク壼セョ菫。 逧<>ョ梧紛髣ュ邇?
> **鬚<>シー蟾・菴憺<E88FB4>?*: 2螟ゥ<E89E9F><EFBDA9>ay 3-4<>?
> **譬ク蠢<EFBDB8>炊蠢オ**: 蜈域遠騾壽怙蟆城溜邇ッ<E98287>碁ェ瑚ッ∵橿譛ッ蜿ッ陦梧€<C280><EFBFBD>騾先ュ・荳ー蟇悟粥閭ス
---
## <20>識 荳€VP螳壻ケ我ク守岼譬?
### 1.1 莉€荵域弍譛€蟆城溜邇ッ<E98287><EFBDAF>
**譬ク蠢<EFBDB8>溜邇ッ**<EFBFBD>?```
REDCap蠖募<EFBFBD>謨ー謐ョ 竊?Node.js螳樊慮謐戊執 竊?莨∽ク壼セョ菫。譎コ閭ス騾夂衍 竊?PI蟇ケ隸晄衍隸「
```
**鬪瑚ッ∽サキ蛟?*<2A>?1. 笨?**螳樊慮諢溽衍**<2A>啀I譌<49>€逋サ蠖紐EDCap<61>碁囂譌カ謗梧升鬘ケ逶ョ霑帛ア?2. 笨?**荳サ蜉ィ騾夂衍**<2A>壽焚謐ョ蠖募<E8A096>蜷守ォ句叉謗ィ騾<EFBDA8>シ御ク堺シ夐<EFBCA0>
3. 笨?**譎コ閭ス莠、莠<EFBDA4>**<2A>壼惠莨∽ク壼セョ菫。荳ュ蜊ウ蜿ッ譟・隸「謨ー謐ョ縲∬執蜿匁冠蜻?4. 笨?**譏捺黄螻?*<2A>夐溜邇ッ謇馴€壼錘<E5A3BC>悟庄莉・蠢ォ騾滓キサ蜉<EFBDBB>雍ィ謗ァ縲∵署驢偵€∫サ溯ョ。遲牙粥閭ス
### 1.2 證ゆク榊ョ樒鴫逧<E9B4AB>粥閭ス<E996AD>亥錘扈ュ謇ゥ螻包シ?
- 竢ク<E7ABA2><EFBDB8> **謨ー謐ョ雍ィ謗ァ隗<EFBDA7><E99A97>逕滓<E98095>**<2A><>hase 1.5<EFBFBD>会シ壻ク贋シ<EFBFBD>遐皮ゥカ譁ケ譯<EFBFBD> 竊?AI逕滓<E98095><EFBFBD><E99A97>蠎?竊?蝓コ莠手ァ<E6898B><EFBDA7>雍ィ謗ァ
- 竢ク<E7ABA2><EFBDB8> **PC Workbench蜑咲ォッ**<2A><>hase 2<>会シ壼、肴<EFBDA4>クAI蟒コ隶ョ逧Цeb逡碁擇
- 竢ク<E7ABA2><EFBDB8> **REDCap謨ー謐ョ蝗槫<E89D97>**<2A><>hase 2<>会シ哂I蟒コ隶ョ螳。謇ケ蜷主屓蜀吝芦REDCap
- 竢ク<E7ABA2><EFBDB8> **蠕ョ菫。蟆冗ィ句コ?*<2A><>hase 3<>会シ夂ァサ蜉ィ遶ッ蜴溽函菴馴ェ?- 竢ク<E7ABA2><EFBDB8> **螟肴揩蟇ケ隸晁<E99AB8><EFBFBD>**<2A><>hase 3<>会シ壼、夊スョ蟇ケ隸昴€∽ク贋ク区枚逅<E69E9A>ァ」
---
## <20>投 莠後€∝ス灘燕迥カ諤∵€サ扈<EFBDBB>
### 2.1 蟾イ螳梧<E89EB3><EFBFBD>㊥螟<E38AA5>キ・菴懶シ<E687B6>ay 1-2<>?
#### 笨?Day 1<>夂識蠅<E8AD98><E8A085>蟋句喧<E58FA5>?026-01-01<30>?
**謨ー謐ョ蠎?*<2A>?- 笨?蛻帛サコ `iit_schema`<60>?荳ェ陦ィ<E999A6>?- 笨?Prisma Schema螳梧紛<E6A2A7><E7B49B>itProject, IitPendingAction, IitTaskRun, IitUserMapping, IitAuditLog<6F>?- 笨?CRUD豬玖ッ暮€夊ソ<E5A48A>シ?1/11<31>?
**莨∽ク壼セョ菫。**<2A>?- 笨?莨∽ク壼セョ菫。蠑€蜿題€<E9A18C>エヲ蜿キ豕ィ蜀?- 笨?閾ェ蟒コ蠎皮畑蛻帛サコ<EFBDBB><EFBDBA>IT Manager Agent<6E>?- 笨?蜃ュ隸∬執蜿厄シ? - **CorpID**: `ww01cb7b72ea2db83c`
- **AgentID**: `1000002`
- **Secret**: `F3XqlAqKdcOKHi9pLGv5a2dSUowWbevdcDRrBk2pXLM`
- 笨?**鄂鷹。オ謗域揀蜿開S-SDK謗域揀蟾イ闔キ蜿?*
- 笨?**蜿ッ菫。蝓溷錐驟咲スョ謌仙粥**<2A>啻iit.xunzhengyixue.com`
- 笨?**蝓溷錐鬪瑚ッ∵枚莉カ驛ィ鄂イ**<2A>啻WW_verify_YnhsQBwI0ARnNoG0.txt`
- 笨?**Access Token闔キ蜿匁オ玖ッ暮€夊ソ<E5A48A>**
**讓。蝮鈴ェィ譫カ**<EFBFBD>?- 笨?逶ョ蠖慕サ捺桷蛻帛サコ
- 笨?邀サ蝙句ョ壻ケ牙ョ梧紛<E6A2A7>?23陦鯉シ<E9AF89>
- 笨?霍ッ逕ア蜑咲シ€驟咲スョ<EFBDBD><EFBDAE>/api/v1/iit`<60>?
---
#### 笨?Day 2<>啌EDCap螳樊慮髮<E685AE><E9ABAE><EFBFBD>?026-01-02<30>?
**譬ク蠢<EFBDB8>コ、莉倡<E88E89>?*<2A><>2,200陦御サ」遐<EFBDA3>シ会シ?1. 笨?**RedcapAdapter.ts**<2A>?71陦鯉シ<E9AF89>
- `exportRecords()` - 蟇シ蜃コ隶ー蠖包シ域髪謖∝<E8AC96>驥?蠅樣㍼/謖<>ョ夊ョー蠖包シ? - `exportMetadata()` - 蟇シ蜃コ蟄玲ョオ螳壻ケ<E5A3BB>
- `importRecords()` - 蟇シ蜈・隶ー蠖包シ磯「<E7A3AF><EFBFBD><E89597>
- `testConnection()` - 霑樊磁豬玖ッ<E78E96>
2. 笨?**WebhookController.ts**<2A>?27陦鯉シ<E9AF89>
- `handleWebhook()` - 謗・謾カREDCap DET隗ヲ蜿托シ?10ms蜩榊コ費シ? - 蟷らュ画€ァ譽€譟・<E8AD9F>磯亟豁「驥榊、榊、<E6A68A><EFBFBD>? - 螳。隶。譌・蠢苓ョー蠖<EFBDB0>
- 謗ィ騾∝芦雍ィ謗ァ髦溷<E9ABA6><E6BAB7><EFBFBD>iit_quality_check`<60>?
3. 笨?**SyncManager.ts**<2A>?98陦鯉シ<E9AF89>
- `initScheduledJob()` - 蛻晏ァ句喧螳壽慮莉サ蜉。<E89C89>域ッ?蛻<><EFBFBD>? - `handlePoll()` - 霓ョ隸「謇€譛餌ctive鬘ケ逶ョ
- `manualSync()` - 謇句勘蜷梧ュ・
- `fullSync()` - 蜈ィ驥丞酔豁・
4. 笨?**Worker豕ィ蜀<EFBDA8>**<2A>?1陦鯉シ<E9AF89>
- `iit_quality_check` - 雍ィ謗ァ莉サ蜉。<E89C89>亥キイ豕ィ蜀鯉シ悟セ<E6829F>。・蜈<EFBDA5>€サ霎托シ? - `iit_redcap_poll` - 螳壽慮霓ョ隸「莉サ蜉。
5. 笨?**霍ッ逕ア驟咲スョ**<2A>?03陦鯉シ<E9AF89>
- `/api/v1/iit/health` - 蛛・蠎キ譽€譟? - `/api/v1/iit/webhooks/redcap` - DET蝗櫁ー<E6AB81>磁謾カ<E8ACBE>域髪謖orm-urlencoded<65>? - `/api/v1/iit/webhooks/health` - Webhook蛛・蠎キ譽€譟? - `/api/v1/iit/projects/:id/sync` - 謇句勘蜷梧ュ・
- `/api/v1/iit/projects/:id/full-sync` - 蜈ィ驥丞酔豁・
**豬玖ッ戊<EFBDAF>譛ャ**<EFBFBD>?12陦鯉シ会シ?- 笨?`test-redcap-api.ts`<EFBFBD>?89陦鯉シ<E9AF89>- API騾る<E9A8BE>蝎ィ豬玖ッ?- 笨?`test-redcap-webhook.ts`<EFBFBD>?74陦鯉シ<E9AF89>- Webhook謗・謾カ蝎ィ豬玖ッ?- 笨?`test-redcap-integration.ts`<EFBFBD>?49陦鯉シ<E9AF89>- 遶ッ蛻ー遶ッ髮<EFBDAF><E9ABAE>豬玖ッ?
**豬玖ッ慕サ捺棡**<EFBFBD>?- 笨?**髮<><E9ABAE>豬玖ッ暮€夊ソ<E5A48A><EFBDBF>?*<2A>?2/12<31>?00%<25>?- 笨?**Webhook蜩榊コ疲慮髣エ**<2A>?10ms<6D>育岼譬?100ms<6D>?- 笨?**DET隗ヲ蜿大サカ霑<EFBDB6>**<2A>?遘抵シ亥ョ樊慮<E6A88A>?- 笨?**謨ー謐ョ蜷梧ュ・蜃<EFBDA5>。ョ諤?*<2A>?00%
**REDCap邇ッ蠅<EFBDAF>**<EFBFBD>?- 笨?REDCap 15.8.0譛ャ蝨ーDocker驛ィ鄂イ
- 笨?豬玖ッ暮。ケ逶ョ蛻帛サコ<EFBDBB><EFBDBA>est0102, PID 16<31>?- 笨?6譚。豬玖ッ墓焚謐ョ蠖募<E8A096>?- 笨?DET驟咲スョ謌仙粥<E4BB99>啻http://host.docker.internal:3001/api/v1/iit/webhooks/redcap`
- 笨?API Token逕滓<E98095><E6BB93>啻FCB30F9CBD12EE9E8E9B3E3A0106701B`
**蜈ウ髞ョ謚€譛ッ遯∫<E981AF>?*<2A>?1. 笨?REDCap DET螳樊慮隗ヲ蜿托シ?遘貞サカ霑滂シ<E6BB82>
2. 笨?form-urlencoded譬シ蠑乗髪謖<E9ABAA><EFBFBD>EDCap蜴溽函譬シ蠑擾シ?3. 笨?蜿御ソ晞勦譛コ蛻カ<E89BBB><EFBDB6>ebhook + 螳壽慮霓ョ隸「<E99AB8>?4. 笨?隨ヲ蜷亥屬髦溷シ€蜿題ァ<E9A18C><EFBFBD>磯弌蛻怜多蜷阪€仝orker豕ィ蜀鯉シ?
---
### 2.2 蠖灘燕譫カ譫<EFBDB6>憾諤?
```
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏? 蟾イ螳梧<E89EB3><EFBFBD>渕遑€隶セ譁ス 笏?笏懌楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏? 笏?笏? 笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏? REDCap 笏? 竊?謨ー謐ョ蠖募<E8A096> 笏?笏? 笏? 15.8.0 笏? 竊?DET驟咲スョ 笨? 笏?笏? 笏披楳笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏?DET隗ヲ蜿托シ?遘貞サカ霑滂シ俄<EFBDBC>? 笏?笏? 竊? 笏?笏? 笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏? Node.js Backend 笏? 笏?笏? 笏? (Fastify + pg-boss) 笏? 笏?笏? 笏懌楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏?笨?WebhookController 笏?竊?謗・謾カDET (<10ms) 笏?笏? 笏?笨?RedcapAdapter 笏?竊?諡牙叙謨ー謐ョ 笏?笏? 笏?笨?SyncManager 笏?竊?霓ョ隸「陦・蜈<EFBDA5> 笏?笏? 笏?笨?Worker髦溷<E9ABA6> 笏?竊?蠑よュ・螟<EFBDA5>炊 笏?笏? 笏?竢?WechatService 笏?竊?蠕<>€蜿?<3F>櫨 笏?笏? 笏披楳笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏?蠕<>遠騾?<3F>櫨 笏?笏? 竊? 笏?笏? 笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏? 莨∽ク壼セョ菫。 笏? 笏?笏? 笏? (蟾イ驟咲ス?笨? 笏? 笏?笏? 笏懌楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏?笨?蠎皮畑蛻帛サコ 笏? 笏?笏? 笏?笨?蜃ュ隸<EFBDAD><E99AB8>鄂ョ 笏? 笏?笏? 笏?笨?蝓溷錐謗域揀 笏? 笏?笏? 笏?笨?AccessToken闔キ蜿<EFBDB7> 笏? 笏?笏? 笏?竢?豸域<E8B1B8>謗ィ騾? 笏?竊?蠕<>€蜿?<3F>櫨 笏?笏? 笏?竢?豸域<E8B1B8>謗・謾カ 笏?竊?蠕<>€蜿?<3F>櫨 笏?笏? 笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?笏? 笏?笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?```
---
## 笞<><E7AC9E><EFBFBD> 荳峨€<C280>髞ョ謚€譛ッ鬟朱勦荳手ァ<E6898B>∩譁ケ譯<EFBDB9>
蝨ィ豁」蠑丞シ€蜿大燕<EFBFBD>?*蠢<>。サ莠<EFBDBB>ァ」**莉・荳<EFBDA5>3荳ェ莨∽ク壼セョ菫。蟇ケ謗・逧<EFBDA5><E980A7>蜻ス髯キ髦ア<E9ABA6>?
### 鬟朱勦A<E58BA6>?遘定カ<E5AE9A>慮鬲泌<E9ACB2>?<3F>櫨 Critical
**髣ョ鬚<EFBDAE>**<2A>壻シ∽ク壼セョ菫。隕∵アり「ォ蜉ィ蝗槫、肴カ域<EFBDB6><EFBFBD>。サ蝨ィ**5遘貞<E98198>**螳梧<E89EB3>縲ょヲよ棡Node.js遲陰I隶。邂怜ョ悟<EFBDAE>return<72>御シ∝セョ譌ゥ蟾イ謠千、?譛榊苅證よ慮荳榊庄逕?蟷カ譁ュ蠑€霑樊磁縲?
**髞呵ッッ蛛壽ウ<E5A3BD>**<2A>?```typescript
笶?async handleCallback(request, reply) {
const answer = await callLLM(message); // 蜿ッ閭ス閠玲慮10遘? return reply.send(answer); // 雜<>慮莠<E685AE><EFBFBD>
}
```
**豁」遑ョ蛛壽ウ<E5A3BD>**<EFBFBD>夐㊦逕?*蠑よュ・蝗槫、肴ィ。蠑<EFBDA1>**
```typescript
?async handleCallback(request, reply) {
// 1. 遶句叉霑泌屓<E6B38C>?1遘抵シ<E68AB5>
reply.send('success');
// 2. 蠑よュ・螟<EFBDA5><EFBFBD>井ク埼仆蝪橸シ? setImmediate(async () => {
const answer = await callLLM(message); // 蜿ッ莉・諷「諷「邂? await wechatService.sendTextMessage(userId, answer); // 荳サ蜉ィ謗ィ騾? });
}
```
**隗<>∩謗ェ譁ス**<EFBFBD>壼惠Day 3蠑€蜿台クュ**蠢<>。サ**菴ソ逕ィ蠑よュ・蝗槫、肴ィ。蠑擾シ檎ヲ∵ュ「蝨ィHTTP Response荳ュ逶エ謗・霑泌屓AI扈捺棡縲?
---
### 鬟朱勦B<E58BA6>唸ML蜉<4C>隗」蟇?<3F>櫨 P0
**髣ョ鬚<EFBDAE>**<EFBFBD>壻シ∽ク壼セョ菫。逧<EFBFBD>カ域<EFBFBD>菴捺弍**蜉<><EFBFBD>噪XML**<2A><>ncrypt蟄玲ョオ<EFBDAE>会シ御ク肴弍譏取枚JSON縲りァ」蟇<EFBDA3>怙隕、ES邂玲ウ募柱螟肴揩逧Пadding隗<67><E99A97>縲?
**髞呵ッッ蛛壽ウ<E5A3BD>**<EFBFBD><EFBFBD>蟾ア蜀吝刈隗」蟇<EFBFBD>ョ玲ウ包シ域栫譏灘<EFBFBD>髞呻シ?
**豁」遑ョ蛛壽ウ<E5A3BD>**<EFBFBD>壻スソ逕ィ螳俶婿蠎<EFBFBD>
```bash
npm install @wecom/crypto
```
```typescript
import { WXBizMsgCrypt } from '@wecom/crypto';
const crypt = new WXBizMsgCrypt(
WECHAT_TOKEN, // 閾ェ螳壻ケ欝oken
WECHAT_ENCODING_AES_KEY, // 莨∝セョ蜷主床逕滓<E98095><E6BB93>?3菴搾シ<E690BE>
WECHAT_CORP_ID
);
// 隗」蟇<EFBDA3>カ域<EFBDB6>
const decrypted = crypt.decrypt(encryptedXml);
```
**隗<>∩謗ェ譁ス**<EFBFBD>壼シコ蛻カ菴ソ逕ィ螳俶婿蠎難シ檎ヲ∵ュ「閾ェ蟾ア螳樒鴫蜉<EFBFBD>隗」蟇<EFBFBD>€?
---
### 鬟朱勦C<E58BA6>唔P逋ス蜷榊黒髯仙<E9ABAF>?<3F>櫨 P0
**髣ョ鬚<EFBDAE>**<EFBFBD>夊執蜿泡ccessToken譌カ<EFBFBD>御シ∽ク壼セョ菫。莨壽<EFBFBD>。鬪瑚ッキ豎よ擂貅蝕P縲?
**邇ー迥カ**<EFBFBD>售AE騾夊ソ⑮AT鄂大<EFBFBD>隶ソ髣ョ螟也ス<EFBFBD>
- **NAT鄂大<E98482>IP**<2A>啻182.92.176.14`
- **莨∽ク壼セョ菫。驟咲スョ**<2A>壽悴豺サ蜉<EFBDBB>蛻?莨∽ク壼庄菫。IP"蛻苓。ィ
**蜷取棡**<EFBFBD>壼ヲゆク埼<EFBFBD>鄂ョ<EFBFBD>携etAccessToken()莨壽冠**60020髞呵ッッ**
**隗<>∩謗ェ譁ス**<EFBFBD>?1. 逋サ蠖穂シ∽ク壼セョ菫。邂。逅<EFBDA1>錘蜿ー
2. 霑帛<E99C91>"蠎皮畑邂。逅<EFBDA1>" 竊?"IIT Manager Agent"
3. 謇セ蛻ー"莨∽ク壼庄菫。IP"驟咲スョ
4. 豺サ蜉<EFBDBB><E89C89>啻182.92.176.14`
---
### 鬟朱勦D<E58BA6><EFBFBD>髞ョ隸榊源驟<E6BA90> vs AI Agent 笞<><E7AC9E><EFBFBD> P2
**髣ョ鬚<EFBDAE>**<EFBFBD>夂ョ€蜊慕噪蜈ウ髞ョ隸榊源驟搾シ<EFBFBD>if (msg.includes('豎<>€?))`<60>我ク肴弍AI Agent<6E>悟宵譏ッif-else譛コ蝎ィ莠コ縲?
**豁」遑ョ蛛壽ウ<E5A3BD>**<2A>壻スソ逕ィLLM蛛壽э蝗セ蛻<EFBDBE>ア?```typescript
// 笨?逵滓ュ」逧БI Agent
const intent = await classifyIntent(userMessage); // 隹<>畑LLM
switch(intent.type) {
case 'query_weekly_summary': ...
case 'query_patient_info': ...
}
```
**隗<>∩謗ェ譁ス**<2A>壼惠Day 3荳句壕螳樒鴫蝓コ莠鮫LM逧<4D>э蝗セ隸<EFBDBE>悪縲?
---
## <20>噫 蝗帙€ay 3-4 蠑€蜿題ョ。蛻?
### Day 3<>壻シ∽ク壼セョ菫。髮<EFBDA1><E9ABAE><EFBFBD><EFBFBD>2026-01-03<30>?蟆乗慮<E4B997>解沐?
#### 蜃<><EFBFBD>キ・菴懶シ壻シ∽ク壼セョ菫。驟咲スョ譽€譟・<E8AD9F><EFBDA5>1蟆乗慮<E4B997>俄國<E4BF84>?蠢<>。サ蜈亥★
**莉サ蜉。0<EFBDA1>壻シ∽ク壼セョ菫。驟咲スョ螳梧紛諤ァ譽€譟?*
**驟咲スョ貂<EFBDAE>黒**<2A>?1. [ ] **莨∽ク壼庄菫。IP驟咲スョ** <20>櫨 Critical
- 逋サ蠖穂シ∽ク壼セョ菫。邂。逅<EFBDA1>錘蜿ー
- 蠎皮畑邂。逅<EFBDA1> 竊?IIT Manager Agent 竊?莨∽ク壼庄菫。IP
- 豺サ蜉<EFBDBB><E89C89>啻182.92.176.14`<EFBFBD><EFBFBD>AE NAT鄂大<E98482>IP<49>? - 豬玖ッ包シ夊ー<E5A48A>畑getAccessToken<65>碁ェ瑚ッ∽ク肴<EFBDB8>?0020髞呵ッッ
2. [ ] **闔キ蜿胞ncodingAESKey** <20>櫨 Critical
- 莨∽ク壼セョ菫。蜷主床 竊?蠎皮畑邂。逅<EFBDA1> 竊?IIT Manager Agent
-€蜿題€<E9A18C>磁蜿?竊?謗・謾カ豸域<E8B1B8>
- 轤ケ蜃サ"髫乗惻逕滓<E98095>"謖蛾聴<E89BBE>瑚執蜿?3菴喉ESKey
- 螟榊宛菫晏ュ假シ育畑莠取カ域<EFBDB6>隗」蟇<EFBDA3><EFBFBD>
3. [ ] **隶セ鄂ョToken** <20>櫨 Critical
- 閾ェ螳壻ケ我ク€荳ェToken<65>育畑莠守ュセ蜷埼ェ瑚ッ<E7919A><EFBFBD>
- 蟒コ隶ョ<E99AB6>?2菴埼囂譛コ蟄礼ャヲ荳イ
- 菫晏ュ伜芦邇ッ蠅<EFBDAF>序驥?
4. [ ] **驟咲スョ蝗櫁ーザRL**
- URL<52>啻https://iit.xunzhengyixue.com/api/v1/iit/wechat/callback`
- 鬪瑚ッゝoken縲・ncodingAESKey驟咲スョ豁」遑ョ
**邇ッ蠅<EFBDAF>序驥乗眠蠅<E79CA0>**<EFBFBD>?```env
# 莨∽ク壼セョ菫。驟咲スョ<EFBDBD>亥キイ譛会シ<E4BC9A>
WECHAT_CORP_ID=ww6ab493470ab4f377
WECHAT_AGENT_ID=1000002
WECHAT_CORP_SECRET=AZIVxMtoLb0rEszXS81e4dBRl-I9kgTjygIS0cFfENU
# 莨∽ク壼セョ菫。蜉<EFBDA1>隗」蟇<EFBDA3><E89F87>鄂ョ<E98482>域眠蠅橸シ解沐?WECHAT_TOKEN=your_32_char_random_token_here
WECHAT_ENCODING_AES_KEY=your_43_char_aes_key_from_wechat_console
```
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?IP逋ス蜷榊黒蟾イ驟咲スョ
- 笨?EncodingAESKey蟾イ闔キ蜿門ケカ菫晏ュ<E6998F>
- 笨?Token蟾イ隶セ鄂ョ蟷カ菫晏ュ<E6998F>
- 笨?AccessToken蜿ッ莉・豁」蟶ク闔キ蜿厄シ域裏60020髞呵ッッ<EFBDAF>?
---
#### 荳雁壕<E99B81>壻シ∽ク壼セョ菫。謗ィ騾∵恪蜉。<E89C89><EFBDA1>4蟆乗慮<E4B997>?
**逶ョ譬<EFBDAE>**<2A>壼ョ梧<EFBDAE>莉晒ode.js蛻ー莨∽ク壼セョ菫。逧<EFBDA1>耳騾<E880B3>€
**莉サ蜉。1<EFBDA1><EFBFBD>蟒?WechatService.ts<74>?蟆乗慮<E4B997>?*
**譁<>サカ菴咲スョ**<2A>啻backend/src/modules/iit-manager/services/WechatService.ts`
**譬ク蠢<EFBDB8>粥閭ス**<EFBFBD>?```typescript
class WechatService {
/**
* 闔キ蜿泡ccess Token<65>亥クヲ郛灘ュ假シ? */
async getAccessToken(): Promise<string>
/**
* 蜿鷹€∵焚謐ョ蠖募<E8A096>騾夂衍
*/
async sendDataEntryNotification(params: {
userId: string;
projectName: string;
recordId: string;
action: 'created' | 'updated';
fieldsSummary: string;
}): Promise<any>
/**
* 蜿鷹€∵枚譛ャ豸域<E8B1B8><E59F9F>€夂畑<E5A482>? */
async sendTextMessage(userId: string, content: string): Promise<any>
/**
* 蜿鷹€∝今迚<E4BB8A>カ域<EFBDB6><E59F9F>€夂畑<E5A482>? */
async sendTextCard(params: {
userId: string;
title: string;
description: string;
url?: string;
btntxt?: string;
}): Promise<any>
}
```
**螳樒鴫隕∫せ**<2A>?- 笨?AccessToken郛灘ュ伜芦Postgres<65>?000遘定ソ<E5AE9A>悄譌カ髣エ<E9ABA3><EFBDB4>
- 笨?驥崎ッ墓惻蛻カ<E89BBB>?谺。驥崎ッ包シ梧欠謨ー騾€驕ソ<E9A995><EFBDBF>
- 笨?髞呵ッッ螟<EFBDAF>炊蜥梧律蠢苓ョー蠖?- 笨?謾ッ謖∵枚譛ャ豸域<E8B1B8>蜥悟今迚<E4BB8A>カ域<EFBDB6>?
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?AccessToken蜿ッ莉・豁」遑ョ闔キ蜿門柱郛灘ュ?- 笨?蜿ッ莉・蜿鷹€∵枚譛ャ豸域<E8B1B8>蛻ー謖<EFBDB0>ョ夂畑謌キ
- 笨?蜿ッ莉・蜿鷹€∝今迚<E4BB8A>カ域<EFBDB6>?- 笨?郛灘ュ俶惻蛻カ豁」蟶ク蟾・菴<EFBDA5>
---
**莉サ蜉。2<EFBDA1>壼ョ悟<EFBDAE>?iit_quality_check Worker<65>?蟆乗慮<E4B997>?*
**譁<>サカ菴咲スョ**<2A>啻backend/src/modules/iit-manager/index.ts`
**蠖灘燕迥カ諤?*<2A>啗orker蟾イ豕ィ蜀鯉シ御ス<E5BEA1>€サ霎台クコ遨コ<E981A8>郁ソ泌屓pending_implementation<6F>?
**譖エ譁ー蜀<EFBDB0>ョケ**<EFBFBD>?```typescript
jobQueue.process('iit_quality_check', async (job) => {
const { projectId, recordId, recordData, instrument } = job.data;
try {
// 1. 闔キ蜿夜。ケ逶ョ驟咲スョ
const project = await prisma.projects.findUnique({
where: { id: projectId }
});
// 2. 譫<>€<EFBFBD>謨ー謐ョ鞫倩ヲ? const fieldsList = Object.keys(recordData);
const summary = `蠖募<EFBFBD>${fieldsList.length}荳ェ蟄玲ョオ`;
// 3. 蜿鷹€∽シ∽ク壼セョ菫。騾夂衍
const wechatService = new WechatService();
await wechatService.sendDataEntryNotification({
userId: 'GaoFeng', // TODO: 莉朱。ケ逶ョ驟咲スョ荳ュ闔キ蜿<EFBDB7>
projectName: project.name,
recordId,
action: instrument === 'demographics' ? 'created' : 'updated',
fieldsSummary: summary
});
// 4. 隶ー蠖募ョ。隶。譌・蠢<EFBDA5>
await prisma.auditLogs.create({
data: {
projectId,
actionType: 'WECHAT_NOTIFICATION_SENT',
entityId: recordId,
details: {
recordId,
instrument,
fieldCount: fieldsList.length,
notified: true
}
}
});
logger.info('Wechat notification sent', {
recordId,
instrument,
fieldCount: fieldsList.length
});
return { success: true, notified: true };
} catch (error: any) {
logger.error('Wechat notification failed', {
recordId,
error: error.message
});
throw error;
}
});
```
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?Worker蜿ッ莉・豁」蟶ク謇ァ陦<EFBDA7>
- 笨?莨∽ク壼セョ菫。騾夂衍蜿鷹€<C280>蜉?- 笨?螳。隶。譌・蠢玲ュ」遑ョ隶ー蠖<EFBDB0>
- 笨?髞呵ッッ螟<EFBDAF>炊螳悟埋
---
**莉サ蜉。3<EFBDA1>夂ォッ蛻ー遶ッ豬玖ッ包シ?蟆乗慮<E4B997>?*
**豬玖ッ募惻譎ッ1<EFBDAF>壽焚謐ョ蠖募<E8A096>騾夂衍**
```
謫堺ス懶シ壼惠REDCap荳ュ譁ー蠅櫁ョー蠖肘D 8
<EFBFBD><EFBFBD>?1. DET螳樊慮隗ヲ蜿托シ?遘貞サカ霑滂シ<E6BB82>
2. WebhookController謗・謾カ<E8ACBE>?10ms蜩榊コ費シ?3. Worker謇ァ陦鯉シ?遘貞<E98198><E8B29E>?4. 莨∽ク壼セョ菫。謾カ蛻ー騾夂衍<E5A482>?遘貞<E98198><E8B29E>?```
**豬玖ッ募惻譎ッ2<EFBDAF>壽焚謐ョ譖エ譁ー騾夂衍**
```
謫堺ス懶シ壼惠REDCap荳ュ菫ョ謾ケ隶ー蠖肘D 2
<EFBFBD><EFBFBD>?1. DET螳樊慮隗ヲ蜿<EFBDA6>
2. 莨∽ク壼セョ菫。謾カ蛻ー譖エ譁ー騾夂衍
3. 騾夂衍蜀<E8A18D>ョケ蛹<EFBDB9>性菫ョ謾ケ逧<EFBDB9>ュ玲ョオ菫。諱?```
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?螳梧紛髣ュ邇ッ<E98287><EFBDAF>EDCap 竊?Node.js 竊?莨∝セョ<EFBDBE>画遠騾?- 笨?蜩榊コ疲慮髣エ<5遘?- 笨?騾夂衍蜀<E8A18D>ョケ蜃<EFBDB9>。ョ
- 笨?螳。隶。譌・蠢怜ョ梧紛
---
#### 荳句壕<E58FA5>壻シ∽ク壼セョ菫。蟇ケ隸晄磁謾カ<E8ACBE><EFBDB6>4蟆乗慮<E4B997>?
**逶ョ譬<EFBDAE>**<2A>壼ョ樒鴫PI蝨ィ莨∽ク壼セョ菫。荳ュ荳拶I Agent蟇ケ隸<EFBDB9>
**莉サ蜉。4<EFBDA1>壼ョ芽」<E88ABD>ケカ驟咲スョ豸域<E8B1B8>隗」蟇<EFBDA3>コ難シ<E99BA3>15蛻<35><EFBFBD>?*
```bash
cd backend
npm install @wecom/crypto
npm install xml2js # XML隗」譫<EFBDA3>
```
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?萓晁オ門ョ芽」<E88ABD><EFBDA3><EFBFBD>
- 笨?蜿ッ莉・import謌仙粥
---
**莉サ蜉。5<EFBDA1><EFBFBD>蟒?WechatCallbackController.ts<74>?.5蟆乗慮<EFBFBD>解沐?蜈ウ髞ョ**
**譁<>サカ菴咲スョ**<2A>啻backend/src/modules/iit-manager/controllers/WechatCallbackController.ts`
**譬ク蠢<EFBDB8>粥閭ス**<EFBFBD>?*蠑よュ・蝗槫、肴ィ。蠑<EFBDA1>**<2A>会シ<E4BC9A>
```typescript
import { WXBizMsgCrypt } from '@wecom/crypto';
import { parseString } from 'xml2js';
class WechatCallbackController {
private crypt: WXBizMsgCrypt;
constructor() {
this.crypt = new WXBizMsgCrypt(
process.env.WECHAT_TOKEN!,
process.env.WECHAT_ENCODING_AES_KEY!,
process.env.WECHAT_CORP_ID!
);
}
/**
* 鬪瑚ッ∽シ∽ク壼セョ菫。遲セ蜷搾シ<E690BE>ET隸キ豎ゑシ? * 莨∽ク壼セョ菫。鬥匁ャ。驟咲スョ蝗櫁ーザRL譌カ莨壼書騾<E69BB8>ェ瑚ッ∬ッキ豎? */
async verifyCallback(request: any, reply: any): Promise<any> {
const { msg_signature, timestamp, nonce, echostr } = request.query;
try {
// 鬪瑚ッ∫ュセ蜷榊ケカ隗」蟇<EFBDA3>chostr
const decrypted = this.crypt.verifyURL(
msg_signature,
timestamp,
nonce,
echostr
);
logger.info('Wechat callback URL verified');
return reply.send(decrypted);
} catch (error: any) {
logger.error('Wechat callback verification failed', { error: error.message });
return reply.code(403).send('Verification failed');
}
}
/**
* 謗・謾カ莨∽ク壼セョ菫。逕ィ謌キ豸域<E8B1B8><E59F9F><EFBFBD>OST隸キ豎ゑシ? * <20>櫨 蜈ウ髞ョ<E9AB9E>壼ソ<E5A3BC>。サ蝨ィ5遘貞<E98198>霑泌屓<E6B38C>御スソ逕ィ蠑よュ・螟<EFBDA5><E89E9F>? */
async handleCallback(request: any, reply: any): Promise<any> {
const { msg_signature, timestamp, nonce } = request.query;
const encryptedXml = request.body;
try {
// 1. 隗」蟇<EFBDA3>カ域<EFBDB6>菴? const decryptedXml = this.crypt.decrypt(
msg_signature,
timestamp,
nonce,
encryptedXml
);
// 2. 隗」譫森ML
const message = await this.parseXML(decryptedXml);
const { FromUserName, Content, MsgId, MsgType } = message;
logger.info('Wechat message received', {
userId: FromUserName,
msgType: MsgType,
msgId: MsgId
});
// 3. <20>櫨 遶句叉霑泌屓'success'<27>?1遘抵シ<E68AB5>
reply.send('success');
// 4. <20>櫨 蠑よュ・螟<EFBDA5><EFBFBD>井ク埼仆蝪橸シ悟庄莉・諷「諷「邂暦シ? if (MsgType === 'text') {
setImmediate(async () => {
try {
// 蜿ッ閭ス閠玲慮5-10遘? const answer = await this.processUserMessage(FromUserName, Content);
// 菴ソ逕ィ荳サ蜉ィ謗ィ騾∵磁蜿」霑泌屓扈捺<E68988>? const wechatService = new WechatService();
await wechatService.sendTextMessage(FromUserName, answer);
// 隶ー蠖募ョ。隶。譌・蠢<EFBDA5>
await this.logInteraction(MsgId, FromUserName, Content, answer);
} catch (error: any) {
logger.error('Async message processing failed', {
msgId: MsgId,
error: error.message
});
// 蜿鷹€<E9B7B9>漠隸ッ謠千、? await wechatService.sendTextMessage(
FromUserName,
'謚ア豁会シ悟、<E6829F>炊謔ィ逧<EFBDA8>カ域<EFBDB6>譌カ蜃コ髞吩コ<E590A9>シ瑚ッキ遞榊錘驥崎ッ輔€?
);
}
});
}
return; // 蟾イ扈剰ソ泌屓霑?success'?
} catch (error: any) {
logger.error('Wechat callback failed', { error: error.message });
return reply.code(500).send('Internal error');
}
}
/**
* 螟<>炊逕ィ謌キ豸域<E8B1B8><E59F9F>芋沐?菴ソ逕ィLLM蛛壽э蝗セ隸<EFBDBE><EFBFBD>€碁撼蜈ウ髞ョ隸榊源驟搾シ<E690BE>
*/
private async processUserMessage(
userId: string,
message: string
): Promise<string> {
// 1. 隹<>畑LLM蛛壽э蝗セ隸<EFBDBE><E99AB8>? const intent = await this.classifyIntent(message);
logger.info('Intent classified', { userId, intent });
// 2. 譬ケ謐ョ諢丞崟謇ァ陦悟ッケ蠎疲桃菴<E6A183>
try {
switch(intent.type) {
case 'query_weekly_summary':
return await this.getWeeklySummary(intent.params);
case 'query_patient_info':
return await this.getPatientInfo(intent.params.recordId);
case 'query_project_stats':
return await this.getProjectStats(intent.params.projectId);
case 'unknown':
default:
return this.getHelpMessage();
}
} catch (error: any) {
logger.error('Query execution failed', { intent, error: error.message });
throw error;
}
}
/**
* <20>櫨 菴ソ逕ィLLM蛛壽э蝗セ蛻<EFBDBE>アサ<EFBDB1>育悄豁」逧БI Agent<6E>? */
private async classifyIntent(message: string): Promise<{
type: string;
params: any;
}> {
const prompt = `
<EFBFBD>譏ッ荳€荳ェ諢丞崟蛻<EFBFBD>アサ蝎ィ縲ら畑謌キ隸エ<EFBFBD>?${message}"
隸キ蛻、譁ュ逕ィ謌キ逧<EFBFBD>э蝗セ蟷カ謠仙叙蜿よ焚<EFBFBD>瑚ソ泌屓JSON譬シ蠑擾シ?
諢丞崟邀サ蝙具シ?- query_weekly_summary: 譟・隸「譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€?- query_patient_info: 譟・隸「謔」閠<EFBDA3>ソ。諱?- query_project_stats: 譟・隸「鬘ケ逶ョ扈溯ョ。
- unknown: 譌<>豕戊ッ<E6888A>
遉コ萓具シ?逕ィ謌キ<E8AC8C>?逵狗恚霑吝捉譛画イ。譛画眠逞<E79CA0>ココ<EFBDBA>?
霑泌屓<EFBFBD>嘴"type": "query_weekly_summary", "params": {"timeRange": "this_week"}}
逕ィ謌キ<EFBFBD>?謔」閠?逧<>ュ蜀オ諤惹ケ域<EFBDB9><EFBFBD><EFBDB7>"
霑泌屓<EFBFBD>嘴"type": "query_patient_info", "params": {"recordId": "8"}}
逕ィ謌キ<EFBFBD>?鬘ケ逶ョ霑帛コヲ螯ゆス包シ?
霑泌屓<EFBFBD>嘴"type": "query_project_stats", "params": {}}
隸キ霑泌屓JSON<EFBFBD>? `.trim();
try {
// 隹<>畑DeepSeek API<50><EFBFBD>蜈カ莉豊LM<4C>? const response = await this.callLLM(prompt);
const intent = JSON.parse(response);
return intent;
} catch (error: any) {
logger.error('Intent classification failed', {
message,
error: error.message
});
// 髯咲コァ<EFBDBA>夊ソ泌屓unknown
return { type: 'unknown', params: {} };
}
}
/**
* 隹<>畑LLM API
*/
private async callLLM(prompt: string): Promise<string> {
// TODO: 螳樒鴫DeepSeek API隹<49>
// 證よ慮霑泌屓mock謨ー謐ョ逕ィ莠取オ玖ッ<E78E96>
// 邂€蜊慕噪蜈ウ髞ョ隸榊源驟堺ス應クコfallback
if (prompt.includes('荳€蜻?) || prompt.includes('<EFBFBD>€?)) {
return JSON.stringify({
type: 'query_weekly_summary',
params: { timeRange: 'this_week' }
});
}
const patientMatch = prompt.match(/謔」閠?\d+)/);
if (patientMatch) {
return JSON.stringify({
type: 'query_patient_info',
params: { recordId: patientMatch[1] }
});
}
if (prompt.includes('霑帛コヲ') || prompt.includes('扈溯ョ。')) {
return JSON.stringify({
type: 'query_project_stats',
params: {}
});
}
return JSON.stringify({ type: 'unknown', params: {} });
}
/**
* 闔キ蜿匁怙霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€? */
private async getWeeklySummary(params: any): Promise<string>
/**
* 闔キ蜿匁ぅ閠<E38185>ソ。諱? */
private async getPatientInfo(recordId: string): Promise<string>
/**
* 闔キ蜿夜。ケ逶ョ扈溯ョ。
*/
private async getProjectStats(projectId: string): Promise<string>
/**
* 蟶ョ蜉ゥ豸域<E8B1B8>
*/
private getHelpMessage(): string {
return `謔ィ螂ス<EFBFBD><EFBFBD>譏ッIIT Manager AI蜉ゥ謇<EFBDA9> <20><EFBFBD>
謔ィ蜿ッ莉・霑呎<EFBFBD>キ髣ョ謌托シ<EFBFBD>
<EFBFBD>投 "譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€?
<EFBFBD>側 "譟・隸「謔」閠?逧<>ュ蜀?
<EFBFBD>嶋 "鬘ケ逶ョ霑帛コヲ螯ゆス<E38286>"
謌台シ壼ース蜉帛クョ蜉ゥ謔ィ<EFBFBD>;
}
/**
* 隗」譫森ML豸域<E8B1B8>
*/
private async parseXML(xml: string): Promise<any> {
return new Promise((resolve, reject) => {
parseString(xml, { explicitArray: false }, (err, result) => {
if (err) reject(err);
else resolve(result.xml);
});
});
}
/**
* 隶ー蠖穂コ、莠呈律蠢<E5BE8B>
*/
private async logInteraction(
msgId: string,
userId: string,
userMessage: string,
botResponse: string
): Promise<void> {
await prisma.auditLogs.create({
data: {
actionType: 'WECHAT_USER_MESSAGE',
entityId: userId,
details: {
msgId,
userMessage,
botResponse,
timestamp: new Date()
}
}
});
}
}
```
**螳樒鴫隕∫せ<E288AB><EFBFBD>髞ョ菫ョ豁」<E8B181><EFBDA3>**<EFBFBD>?- 笨?菴ソ逕ィ `@wecom/crypto` 隗」蟇<EFBDA3>カ域<EFBDB6><E59F9F>井ク崎<EFBDB8>蟾ア螳樒鴫<E6A892>?- 笨?遶句叉霑泌屓'success'<27>?1遘抵シ碁∩蜈<E288A9>5遘定カ<E5AE9A><EFBFBD><E685AE>
- 笨?菴ソ逕ィ `setImmediate` 蠑よュ・螟<EFBDA5>
- 笨?菴ソ逕ィ荳サ蜉ィ謗ィ騾∵磁蜿」霑泌屓扈捺<E68988>?- 笨?菴ソ逕ィLLM蛛壽э蝗セ蛻<EFBDBE>アサ<EFBDB1>€碁撼蜈ウ髞ョ隸榊源驟搾シ<E690BE>
- 笨?螳悟埋逧<E59F8B>漠隸ッ螟<EFBDAF>炊蜥梧律蠢苓ョー蠖<EFBDB0>
**鬪梧噺譬<E599BA>**<EFBFBD>?- 笨?莨∽ク壼セョ菫。蝗櫁ーザRL鬪瑚ッ<E7919A>€夊ソ<E5A48A>
- 笨?蜿ッ莉・謗・謾カ蟷カ隗」蟇<EFBDA3>畑謌キ豸域<E8B1B8>?- 笨?蜩榊コ疲慮髣エ<1遘抵シ亥シよュ・螟<EFBDA5><EFBFBD>?- 笨?LLM諢丞崟隸<E5B49F>悪豁」遑ョ邇?80%
- 笨?蜿ッ莉・豁」遑ョ霑泌屓譟・隸「扈捺棡
---
**莉サ蜉。6<EFBDA1>壽ウィ蜀御シ∽ク壼セョ菫。蝗櫁ー<E6AB81>キッ逕ア<E98095><EFBDB1>30蛻<30><EFBFBD>?*
**譁<>サカ菴咲スョ**<EFBFBD>啻backend/src/modules/iit-manager/routes/index.ts`
**譁ー蠅櫁キッ逕ア**<2A>?```typescript
const wechatCallbackController = new WechatCallbackController();
// 莨∽ク壼セョ菫。蝗櫁ー<E6AB81>ェ瑚ッ<E7919A><EFBFBD>ET<45>?fastify.get(
'/api/v1/iit/wechat/callback',
wechatCallbackController.verifyCallback.bind(wechatCallbackController)
);
// 莨∽ク壼セョ菫。豸域<E8B1B8>謗・謾カ<E8ACBE><EFBDB6>OST<53>?fastify.post(
'/api/v1/iit/wechat/callback',
{
schema: {
body: {
type: 'object'
}
}
},
wechatCallbackController.handleCallback.bind(wechatCallbackController)
);
logger.info('Registered route: GET/POST /api/v1/iit/wechat/callback');
```
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?霍ッ逕ア豕ィ蜀梧<E89C80><EFBFBD>
- 笨?GET隸キ豎ょ庄莉・鬪瑚ッ∫ュセ蜷<EFBDBE>
- 笨?POST隸キ豎ょ庄莉・謗・謾カ豸域<E8B1B8>
---
**莉サ蜉。7<EFBDA1>壼ッケ隸晏粥閭ス豬玖ッ包シ<E58C85>1蟆乗慮<E4B997>?*
**豬玖ッ募惻譎ッ1<EFBDAF>壽怙霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€?*
```
謫堺ス懶シ壼惠莨∽ク壼セョ菫。荳ュ蜿鷹€<EFBFBD><EFBFBD>"譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€?
<EFBFBD><EFBFBD>?AI Agent蝗槫、搾シ?"<22>投 譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€<C280><EFBDBB>
譁ー蠅槫女隸戊€<EFBFBD><EFBFBD>2萓?謨ー謐ョ譖エ譁ー<E8AD81>?谺?諤サ隶。<E99AB6>?譚。謫堺ス懆ョー蠖?
```
**豬玖ッ募惻譎ッ2<EFBDAF>壽ぅ閠<E38185>ソ。諱ッ譟・隸?*
```
謫堺ス懶シ壼惠莨∽ク壼セョ菫。荳ュ蜿鷹€<EFBFBD><EFBFBD>"譟・隸「謔」閠?逧<>ュ蜀?
<EFBFBD><EFBFBD>?AI Agent蝗槫、搾シ?"<22>搭 謔」閠?4 蝓コ譛ャ菫。諱ッ<E8ABB1>?蟋灘錐<E78198>嗾est 4 test 4
蟷エ鮴<EFBFBD>シ?8蟯?諤ァ蛻ォ<E89BBB>夂塙
BMI<EFBFBD>?8.3
蠖募<EFBFBD>迥カ諤<EFBFBD>シ壼キイ螳梧<EFBFBD>?
```
**豬玖ッ募惻譎ッ3<EFBDAF>夐。ケ逶ョ霑帛コヲ譟・隸?*
```
謫堺ス懶シ壼惠莨∽ク壼セョ菫。荳ュ蜿鷹€<EFBFBD><EFBFBD>"鬘ケ逶ョ霑帛コヲ"
<EFBFBD><EFBFBD>?AI Agent蝗槫、搾シ?"<22>投 test0102 鬘ケ逶ョ扈溯ョ。<EFBDAE>?諤サ蜿苓ッ戊€<E6888A><EFBFBD>?萓?譛ャ蜻ィ譁ー蠅橸シ?萓?謨ー謐ョ螳梧紛邇<E7B49B><EFBFBD>87.5%"
```
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?3荳ェ豬玖ッ募惻譎ッ蜈ィ驛ィ騾夊ソ<E5A48A>
- 笨?蝗槫、榊<EFBDA4>螳ケ蜃<EFBDB9>。ョ
- 笨?蜩榊コ疲慮髣エ<3遘?- 笨?髞呵ッッ螟<EFBDAF>炊蜿句・ス
---
### <20>投 Day 3 螳梧<E89EB3>諤サ扈難シ?026-01-03<30>俄怛
**螳樣刔螳梧<E89EB3>譌カ髣エ**<2A>?026-01-03
**莉サ蜉。螳梧<E89EB3>蠎?*<2A>?00%
#### 譬ク蠢<EFBDB8><E8A0A2><EFBFBD>
| 莠、莉倡<E88E89>?| 莉」遐<EFBDA3><E98190>?| 迥カ諤?|
|-------|--------|------|
| WechatService<63>井シ∽ク壼セョ菫。謗ィ騾<EFBDA8><EFBFBD> | 314陦?| 笨?螳梧<E89EB3> |
| WechatCallbackController<65>亥屓隹<E5B193><EFBFBD><EFBFBD><E7828A> | 501陦?| 笨?螳梧<E89EB3> |
| 雍ィ謗ァWorker螳悟埋 | 336陦?| 笨?螳梧<E89EB3> |
| Worker豕ィ蜀御ソョ螟搾シ<E690BE>initIitManager`<EFBFBD>?| - | 笨?螳梧<E89EB3> |
| 謨ー謐ョ蠎灘ュ玲ョオ菫ョ螟搾シ<E690BE>action_type`<60>?| - | 笨?螳梧<E89EB3> |
| 遶ッ蛻ー遶ッ豬玖ッ?| - | 笨?騾夊ソ<E5A48A> |
| WECHAT_ENV_CONFIG.md | 401陦?| 笨?螳梧<E89EB3> |
| **諤サ隶。** | **1,755陦?* | **笨?螳梧<E89EB3>** |
#### 蜈ウ髞ョ驥檎ィ狗「?
<EFBFBD>識 **MVP髣ュ邇ッ螳悟<E89EB3>謇馴€?*<2A>?```
REDCap蠖募<EFBFBD>謨ー謐ョ 竊?Node.js螳樊慮謐戊執<E6888A>?10ms<6D>? 竊?Worker螟<72><EFBFBD><E7828A>50ms<6D>? 竊?莨∽ク壼セョ菫。謗ィ騾<EFBDA8>€夂衍<E5A482>?2遘抵シ<E68AB5>
竊?謇区惻遶ッ謗・謾カ笨<EFBDB6>
```
#### 諤ァ閭ス謖<EFBDBD><E8AC96><EFBFBD>
| 謖<><E8AC96><EFBFBD> | 逶ョ譬<EFBDAE> | 螳樣刔 | 迥カ諤?|
|------|------|------|------|
| Webhook蜩榊コ疲慮髣エ | <10ms | 5.8ms | 笨?雜<><E99B9C><EFBFBD>悄 |
| Worker謇ァ陦梧慮髣エ | <100ms | ~50ms | 笨?雜<><E99B9C><EFBFBD>悄 |
| 遶ッ蛻ー遶ッ蟒カ霑?| <5遘?| <2遘?| 笨?雜<><E99B9C><EFBFBD>悄 |
| 豸域<E8B1B8>蜿鷹€<C280>蜉溽紫 | >99% | 100% | 笨?雜<><E99B9C><EFBFBD>悄 |
#### 豬玖ッ暮ェ瑚ッ<E7919A>
**遶ッ蛻ー遶ッ豬玖ッ?*<2A>亥キイ騾夊ソ<E5A48A>シ会シ<E4BC9A>
- 笨?REDCap蛻帛サコ隶ー蠖<EFBDB0> ID 9
- 笨?DET螳樊慮隗ヲ蜿托シ?遘貞サカ霑滂シ<E6BB82>
- 笨?Webhook謗・謾カ<E8ACBE>?.8ms蜩榊コ費シ?- 笨?莉サ蜉。謗ィ騾∝芦pg-boss髦溷<E9ABA6>
- 笨?Worker謇ァ陦瑚エィ謗ァ譽€譟?- 笨?蜿鷹€∽シ∽ク壼セョ菫。騾夂衍
- 笨?謇区惻遶ッ謌仙粥謗・謾カ騾夂衍
- 笨?螳。隶。譌・蠢苓ョー蠖墓<E8A096><EFBFBD>
- 笨?譌<>蠕ェ邇ッ蜿鷹€<E9B7B9>琉鬚?
**莨∽ク壼セョ菫。謗ィ騾∵オ玖ッ?*<2A>亥キイ騾夊ソ<E5A48A>シ会シ<E4BC9A>
- 笨?譁<>悽豸域<E8B1B8>謗ィ騾∵<E9A8BE>蜉?- 笨?Textcard蜊。迚<EFBDA1>カ域<EFBDB6>謗ィ騾∵<E9A8BE>蜉?- 笨?Markdown豸域<E8B1B8>謗ィ騾∵<E9A8BE>蜉?- 笨?謇区惻遶ッ蜈ィ驛ィ謗・謾カ豁」蟶?
#### 謚€譛ッ莠ョ轤?
1. **蠑よュ・Worker譫カ譫<EFBDB6>**<2A>夂ャヲ蜷<EFBDA6>ostgres-Only譛€菴ウ闌<EFBDB3>シ?2. **莨∽ク壼セョ菫。豸域<E8B1B8><EFBFBD>隗」蟇?*<2A>壼ョ梧紛螳樒鴫遲セ蜷埼ェ瑚ッ∝柱蜉<E69FB1>隗」蟇?3. **蠑よュ・蝗槫、肴ィ。蠑<EFBDA1>**<2A>啻setImmediate` 遑ョ菫<EFBDAE>5遘貞<E98198>蜩榊コ<E6A68A>
4. **螳梧紛逧<E7B49B>漠隸ッ螟<EFBDAF><E89E9F>?*<2A>壼ョ。隶。譌・蠢怜、ア雍・荳榊スア蜩堺クサ豬∫ィ?5. **pg-boss驥崎ッ墓惻蛻カ**<EFBFBD><EFBFBD>蜉ィ驥崎ッ?谺。<E8B0BA>檎。ョ菫晏庄髱<E5BA84>諤?
#### 荳エ譌カ謗ェ譁ス荳取橿譛ッ蛟コ蜉。
| 蠎丞捷 | 荳エ譌カ謗ェ譁ス | 謾ケ霑幄ョ。蛻<EFBDA1> |
|------|---------|---------|
| 1 | UserID遑ャ郛也<E9839B><E4B99F>シ育識蠅<E8AD98>序驥擾シ?| Phase 2: 莉朱。ケ逶ョ驟咲スョ陦ィ隸サ蜿<EFBDBB> |
| 2 | 螳壽慮霓ョ隸「遖∫畑 | Phase 2: 菴ソ逕ィnode-cron謌匁黄螻姫gBossQueue |
| 3 | 雍ィ謗ァ騾サ霎醍ョ€蛹厄シ域裏AI<41>?| Phase 1.5: 髮<><E9ABAE>Dify RAG |
| 4 | `notification_config`蟄玲ョオ譛ェ蛻帛サ?| Phase 2: 豺サ蜉<EFBDBB>JSONB蟄玲ョオ |
| 5 | Access Token蜀<6E>ュ倡シ灘ュ<E78198> | Phase 2: 菴ソ逕ィRedis謌匁焚謐ョ蠎<EFBDAE> |
#### 髣ョ鬚倅ク手ァ」蜀?
1. **Worker譛ェ豕ィ蜀?*<2A>啻initIitManager()` 譛ェ隹<EFBDAA><E99AB9>?竊?蝨?`src/index.ts` 荳ュ豺サ蜉<EFBDBB><EFBFBD><E99AB9>?2. **蟄玲ョオ蜷埼漠隸?*<2A>啻action` 竊?`action_type`<EFBFBD>?螟<>ソョ螟搾シ<E690BE>
3. **蠕ェ邇ッ蜿鷹€?*<2A>壼ョ。隶。譌・蠢鈴漠隸ッ蟇シ閾エWorker螟ア雍・驥崎ッ<E5B48E> 竊?豺サ蜉<EFBDBB>try-catch
4. **`notification_config`荳榊ュ伜<EFBFBD>?*<2A>夂ァサ髯、蟄玲ョオ譟・隸「<E99AB8>檎峩謗・菴ソ逕ィ邇ッ蠅<EFBDAF>序驥<E5BA8F>
#### 蜿り€<E3828A>枚譯?
- `06-蠑€蜿題ョー蠖?Day3-莨∽ク壼セョ菫。髮<EFBDA1><E9ABAE>荳守ォッ蛻ー遶ッ豬玖ッ募ョ梧<EFBDAE>隶ー蠖<EFBDB0>.md`
- `backend/WECHAT_ENV_CONFIG.md`
---
### <20>投 Phase 1.5<EFBFBD>哂I蟇ケ隸晁<EFBFBD>蜉幢シ?026-01-03 & 2026-01-04<30>俄怛
**莉サ蜉。逶ョ譬<EFBDAE>**<EFBFBD>壼惠莨∽ク壼セョ菫。荳ュ螳樒鴫AI蟇ケ隸晄衍隸「閭ス蜉<EFBFBD>
**螳樣刔螳梧<E89EB3>譌カ髣エ**<EFBFBD>?- Day 3 荳句壕<E58FA5>?026-01-03<30>会シ壼渕遑€蟇ケ隸<EFBDB9> + REDCap髮<70><E9ABAE>
- Day 4 荳雁壕<E99B81>?026-01-04<30>会シ咼ify遏・隸<EFBDA5>コ馴寔謌?
**莉サ蜉。螳梧<E89EB3>蠎?*<2A>?00%
#### 譬ク蠢<EFBDB8><E8A0A2>譫懶シ<E687B6>hase 1.5<EFBFBD>?
| 莠、莉倡<E88E89>?| 莉」遐<EFBDA3><E98190>?| 迥カ諤?|
|-------|--------|------|
| ChatService.ts<74>亥ッケ隸晄恪蜉。<E89C89><EFBDA1> | 485陦?| 笨?螳梧<E89EB3> |
| SessionMemory.ts<74>井シ夊ッ晁ョー蠢<EFBDB0><EFBFBD> | 120陦?| 笨?螳梧<E89EB3> |
| WechatCallbackController<65>亥ッケ隸晞寔謌撰シ<E692B0> | 譖エ譁ー | 笨?螳梧<E89EB3> |
| Dify遏・隸<EFBDA5>コ灘<EFBDBA>閨?| 閼壽悽 | 笨?螳梧<E89EB3> |
| 諢丞崟隸<E5B49F>悪莨伜喧 | 謇ゥ螻<EFBDA9> | 笨?螳梧<E89EB3> |
| Bug菫ョ螟搾シ亥ュ玲ョオ霍ッ蠕<EFBDAF><EFBFBD> | 蜈ウ髞ョ菫ョ螟<EFBDAE> | 笨?螳梧<E89EB3> |
| 隹<>ッ戊<EFBDAF>譛ャ<E8AD9B>?荳ェ<E88DB3><EFBDAA> | 280陦?| 笨?螳梧<E89EB3> |
| 蠑€蜿題ョー蠖墓枚譯?| 600+陦?| 笨?螳梧<E89EB3> |
| **諤サ隶。** | **~1,485陦?* | **笨?螳梧<E89EB3>** |
#### 蜈ウ髞ョ驥檎ィ狗「?
<EFBFBD>識 **豺キ蜷域」€邏「譫カ譫<EFBDB6>ョ樒<EFBDAE>?*<2A>?```
逕ィ謌キ謠宣琉<EFBFBD>井シ∽ク壼セョ菫。<EFBFBD><EFBFBD>
竊?諢丞崟隸<E5B49F><EFBFBD><E682AA>hatService.detectIntent<6E>? 竊?笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?query_protocol笏?query_record 笏?count_records笏?笏? (譁<>。」譟・隸「) 笏? (隶ー蠖墓衍隸「) 笏? (扈溯ョ。譟・隸「) 笏?笏披楳笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏エ笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏エ笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏? 竊? 竊? 竊? Dify API REDCap API REDCap API
(遏・隸<EFBDA5>コ? (謔」閠<EFBDA3>焚謐? (謔」閠<EFBDA3>焚謐?
竊? 竊? 竊? 譁<>。」迚<EFBDA3>ョオ JSON謨ー謐ョ JSON謨ー謐ョ
竊? 竊? 竊? 笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏エ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 竊? 譫<>サコLLM Prompt
(System + Context + Data)
竊? DeepSeek-V3
竊? AI蝗樒ュ<E6A892>
```
#### 蜉溯<E89C89>鬪瑚ッ<E7919A>
**豬玖ッ暮。ケ逶ョ**: test0102
- REDCap PID: 16, 11譚。隶ー蠖?- Dify Dataset ID: `b49595b2-bf71-4e47-9988-4aa2816d3c6f`
- 譁<>。」: 遐皮ゥカ譁ケ譯医€RF陦ィ譬シ<E8ADAC>?荳ェ譁<EFBDAA>サカ<EFBDBB>悟キイ螟<EFBDB2><EFBFBD><E7828A>
**豬玖ッ募惻譎ッ**<2A>?
| 蝨コ譎ッ | 逕ィ謌キ髣ョ鬚<EFBDAE> | 謨ー謐ョ貅?| 扈捺棡 | 迥カ諤?|
|------|---------|--------|------|------|
| 譁<>。」譟・隸「 | "霑吩クェ遐皮ゥカ逧<EFBDB6>賜髯、譬<EFBDA4>㊥譏ッ莉€荵茨シ<E88CA8>" | Dify | 蝓コ莠取枚譯」蜃<EFBDA3>。ョ蝗樒ュ<E6A892> | 笨?騾夊ソ<E5A48A> |
| CRF譟・隸「 | "CRF陦ィ譬シ荳ュ譛牙頭莠幄ァょッ滓欠譬<E6ACA0>シ? | Dify | 蝓コ莠取枚譯」蜃<EFBDA3>。ョ蝗樒ュ<E6A892> | 笨?騾夊ソ<E5A48A> |
| 謔」閠<EFBDA3>衍隸?| "ID 7逧<37>ぅ閠<E38185>ュ蜀? | REDCap | 螳悟<E89EB3>蛹ケ驟咲悄螳樊焚謐ョ | 笨?騾夊ソ<E5A48A> |
| 扈溯ョ。譟・隸「 | "逶ョ蜑榊<E89C91><EFBFBD><EFBFBD>、壼ー台ココ<EFBDBA>? | REDCap | 蜃<>。ョ扈溯ョ。11莠?| 笨?騾夊ソ<E5A48A> |
| 豺キ蜷域衍隸「 | "霑吩クェ遐皮ゥカ逧<EFBDB6>クサ隕∫<E99A95>皮ゥカ逶ョ逧<EFBDAE>弍莉€荵茨シ<E88CA8>" | Dify | 蝓コ莠取枚譯」蝗樒ュ<E6A892> | 笨?騾夊ソ<E5A48A> |
| 荳贋ク区枚隶ー蠢?| 螟夊スョ蟇ケ隸<EFBDB9> | SessionMemory | 隶ー蠕嶺ク贋ク€霓ョ蜀<EFBDAE>ョ?| 笨?騾夊ソ<E5A48A> |
#### 謚€譛ッ莠ョ轤?
1. **豺キ蜷域」€邏?*<2A>壼酔譌カ謾ッ謖∫サ捺桷蛹匁焚謐ョ<E8AC90><EFBDAE>EDCap<61>牙柱髱樒サ捺桷蛹匁枚譯」<E8ADAF><EFBDA3>ify<66>?2. **譎コ閭ス霍ッ逕ア**<2A><EFBFBD>ケ謐ョ諢丞崟閾ェ蜉ィ騾画叫謨ー謐ョ貅?3. **髦イ豁「蟷サ隗<EFBDBB>**<2A>壽園譛牙屓遲泌渕莠守悄螳樊焚謐?譁<>。」<EFBDA1>檎サ昜ク咲シ夜€?4. **荳贋ク区枚隶ー蠢?*<2A>售essionMemory菫晏ュ俶怙霑?霓ョ蟇ケ隸?5. **螟咲畑LLMFactory**<2A>夐峺驟咲スョ菴ソ逕ィDeepSeek-V3
6. **蜊ウ譌カ蜿埼ヲ<E59FBC>**<2A>?豁」蝨ィ譟・隸「"豸域<E8B1B8><E59F9F>碁∩蜈咲畑謌キ辟ヲ陌?
#### 髣ョ鬚俶賜譟・荳惹ソョ螟?
**蜈ウ髞ョBug菫ョ螟<EFBDAE>**<2A>?
| 髣ョ鬚<EFBDAE> | 譬ケ蝗<EFBDB9> | 隗」蜀ウ譁ケ譯<EFBDB9> | 迥カ諤?|
|------|------|---------|------|
| AI郛夜€<E5A49C>遲疲。?| 諢丞崟隸<E5B49F>悪蜈ウ髞ョ隸堺ク榊<EFBDB8><E6A68A>育シ?蜈・騾?遲会シ<E4BC9A> | 謇ゥ蜈<EFBDA9><E89C88>髞ョ隸榊<E99AB8>陦?| 笨?蟾イ菫ョ螟?|
| Dify蜀<79>ョケ荳コundefined | 髞呵ッッ逧БPI蜩榊コ泌ュ玲ョオ霍ッ蠕<EFBDAF> | 菫ョ豁」荳コ`record.segment.document.name`蜥形record.segment.content` | 笨?蟾イ菫ョ螟?|
**隹<>ッ募キ・蜈キ**<EFBFBD>?- `debug-dify-injection.ts`<EFBFBD>夊ソス雕ェDify扈捺棡豕ィ蜈・豬∫ィ<EFBFBD>
- `inspect-dify-response.ts`<EFBFBD>壽衍逵汽ify API螳樣刔霑泌屓扈捺桷
#### 譬ク蠢<EFBDB8><E8A0A2><EFBFBD>
1. 笨?**螳樊慮謨ー謐ョ譟・隸「**<2A>€夊ソ⑲EDCap API譟・隸「謔」閠<EFBDA3>RF謨ー謐ョ
2. 笨?**遐皮ゥカ譁ケ譯域衍隸「**<2A>€夊ソ⑤ify遏・隸<EFBDA5>コ捺」€邏「遐皮ゥカ譁ケ譯医€RF縲∽シヲ逅<EFBDA6>枚莉?3. 笨?**譎コ閭ス逅<EFBDBD>ァ」**<2A><EFBFBD>辟カ隸ュ險€謠宣琉<E5AEA3>梧裏髴€隶ー蠢<EFBDB0>多莉、
4. 笨?**荳贋ク区枚逅<E69E9A>ァ?*<2A>壼、夊スョ蟇ケ隸晢シ梧髪謖∽サ」隸崎ァ」譫<EFBDA3>
5. 笨?**謨ー謐ョ逵溷ョ樊€?*<2A>壽園譛牙屓遲泌渕莠守悄螳樊焚謐ョ<E8AC90>檎サ昜ク咲シ夜€?6. 笨?**豺キ蜷域」€邏?*<2A>壼酔譌カ譟・隸「螟壻クェ謨ー謐ョ貅撰シ檎サ滉ク€蜻育鴫
#### 蜿り€<E3828A>枚譯?
- [Phase 1.5蠑€蜿題ョ。蛻綻(./Phase1.5-AI蟇ケ隸晁<E99AB8>蜉帛シ€蜿題ョ。蛻?md)
- [Phase 1.5蠑€蜿大ョ梧<EFBFBD>隶ー蠖?(REDCap)](../06-蠑€蜿題ョー蠖?Phase1.5-AI蟇ケ隸晞寔謌審EDCap螳梧<E89EB3>隶ー蠖<EFBDB0>.md)
- [Dify遏・隸<EFBDA5>コ馴寔謌仙シ€蜿題ョー蠖評(../06-蠑€蜿題ョー蠖?2026-01-04-Dify遏・隸<EFBDA5>コ馴寔謌仙シ€蜿題ョー蠖?md)
- [IIT Manager Agent 謚€譛ッ霍ッ蠕<EFBDAF>ク取楔譫<E6A594>ョセ隶。](../02-謚€譛ッ隶セ隶?IIT%20Manager%20Agent%20謚€譛ッ霍ッ蠕<EFBDAF>ク取楔譫<E6A594>ョセ隶。.md)
---
### Day 4<>壼ョ悟埋荳取枚譯」<E8ADAF>?026-01-04<30>?蟆乗慮<E4B997>俄昇<E4BF84>?
#### 荳雁壕<E99B81>壻シ伜喧荳取オ玖ッ包シ?蟆乗慮<E4B997>?
**莉サ蜉。8<EFBDA1>壼ョ悟埋螳。隶。譌・蠢暦シ<E69AA6>1蟆乗慮<E4B997>?*
**譁ー蠅樊律蠢礼アサ蝙<EFBDBB>**<EFBFBD>?```typescript
// 莨∽ク壼セョ菫。莠、莠呈律蠢<E5BE8B>
await prisma.auditLogs.create({
data: {
actionType: 'WECHAT_USER_MESSAGE',
entityId: userId,
details: {
userMessage: message,
botResponse: response,
intent: 'query_patient_info',
timestamp: new Date()
}
}
});
```
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?謇€譛我シ∽ク壼セョ菫。莠、莠帝<E88EA0>譛画律蠢?- 笨?譌・蠢怜桁蜷ォ螳梧紛逧<E7B49B>ク贋ク区枚菫。諱ッ
- 笨?蜿ッ莉・霑ス貅ッ豈乗ャ。蟇ケ隸<EFBDB9>
---
**莉サ蜉。9<EFBDA1>夐漠隸ッ螟<EFBDAF>炊莨伜喧<E4BC9C><E596A7>1蟆乗慮<E4B997>?*
**莨伜喧蜀<E596A7>ョケ**<2A>?1. **莨∽ク壼セョ菫。API隹<49>畑螟ア雍・**<2A>? - 閾ェ蜉ィ驥崎ッ<E5B48E>3谺? - 隶ー蠖暮漠隸ッ譌・蠢<EFBDA5>
- 髯咲コァ螟<EFBDA7><EFBFBD>€夂衍螟ア雍・荳榊スア蜩堺クサ豬∫ィ具シ?
2. **REDCap API雜<49>慮**<2A>? - 30遘定カ<E5AE9A><EFBDB6>? - 蜿句・ス髞呵ッッ謠千、コ
- 霑泌屓郛灘ュ俶焚謐ョ<E8AC90>亥ヲよ棡譛会シ?
3. **逕ィ謌キ豸域<E8B1B8>隗」譫仙、ア雍・**<2A>? - 霑泌屓蜿句・ス謠千、コ
- 隶ー蠖暮漠隸ッ譌・蠢<EFBDA5>
- 荳榊スア蜩榊<E89CA9>莉門粥閭?
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?謇€譛蛾漠隸ッ蝨コ譎ッ譛牙暑螂ス謠千、コ
- 笨?邉サ扈溯<E68988>閾ェ蜉ィ驥崎ッ?- 笨?髞呵ッッ荳榊スア蜩榊<E89CA9>莉紋ササ蜉。謇ァ陦?
---
**莉サ蜉。10<31>壼ョ梧紛髣ュ邇ッ蜴句鴨豬玖ッ包シ<E58C85>1蟆乗慮<E4B997>?*
**豬玖ッ募<EFBDAF>螳ケ**<2A>?1. **霑樒サュ蠖募<E8A096>豬玖ッ<E78E96>**<2A>? - 蝨ィREDCap荳ュ霑樒サュ蠖募<E8A096>?0譚。謨ー謐? - 鬪瑚ッ∵園譛蛾€夂衍驛ス閭ス豁」遑ョ蜿鷹€? - 鬪瑚ッ∵イ。譛蛾@貍丞柱驥榊、?
2. **蟷カ蜿大ッケ隸晄オ玖ッ<E78E96>**<2A>? - 蜷梧慮蜿鷹€?荳ェ譟・隸「隸キ豎? - 鬪瑚ッ∵園譛芽ッキ豎る<E8B18E>閭ス豁」遑ョ蜩榊コ? - 鬪瑚ッ∝桃蠎疲慮髣エ<5遘?
3. **髟ソ譌カ髣エ霑占。梧オ玖ッ?*<2A>? - 邉サ扈溯ソ占。<E58DA0>1蟆乗慮
- 譛滄龍髫乗惻蠖募<E8A096>謨ー謐ョ蜥梧衍隸? - 鬪瑚ッ∫ウサ扈溽ィウ螳壽€?
**鬪梧噺譬<E599BA>㊥**<2A>?- 笨?霑樒サュ蠖募<E8A096>豬玖ッ暮€夊ソ<E5A48A>シ?0/10<31>?- 笨?蟷カ蜿大ッケ隸晄オ玖ッ暮€夊ソ<E5A48A>シ?/5<>?- 笨?髟ソ譌カ髣エ霑占。梧裏蠑ょクク
- 笨?蜀<>ュ伜柱諤ァ閭ス豁」蟶ク
---
#### 荳句壕<E58FA5>壽枚譯」郛門<E9839B><E99680><EFBFBD>3蟆乗慮<E4B997>?
**莉サ蜉。11<31><EFBFBD>蟒コ蠑€蜿大ョ梧<EFBDAE><EFBFBD>。」<EFBDA1><EFBDA3>2蟆乗慮<E4B997>?*
**譁<>。」菴咲スョ**<2A>啻docs/03-荳壼苅讓。蝮<EFBDA1>/IIT Manager Agent/06-蠑€蜿題ョー蠖?Day3-4-譛€蟆舟VP髣ュ邇ッ螳梧<E89EB3>隶ー蠖<EFBDB0>.md`
**譁<>。」蜀<EFBDA3>ョケ**<EFBFBD>?1. 蠑€蜿第ヲりソ?2. 螳梧<E89EB3><EFBFBD>粥閭ス讓。蝮暦シ郁ッヲ扈<EFBDA6>ッエ譏趣シ?3. 豬玖ッ暮ェ瑚ッ∫サ捺棡
4. 諤ァ閭ス謖<EFBDBD><E8AC96><EFBFBD>
5.<>芦逧<E88AA6>琉鬚倅ク手ァ」蜀ウ譁ケ譯<EFBDB9>
6. 髣ュ邇ッ謨域棡貍皮、コ
7. 荳倶ク€豁・隶。蛻?
---
**莉サ蜉。12<31>壽峩譁ー讓。蝮礼憾諤∵枚譯」<E8ADAF><EFBDA3>30蛻<30><EFBFBD>?*
**譁<>。」菴咲スョ**<EFBFBD>啻docs/03-荳壼苅讓。蝮<EFBDA1>/IIT Manager Agent/00-讓。蝮怜ス灘燕迥カ諤∽ク主シ€蜿第欠蜊?md`
**譖エ譁ー蜀<EFBDB0>ョケ**<2A>?- 譖エ譁ー謨エ菴灘ョ梧<EFBDAE>蠎ヲ<E8A08E><EFBDA6>35% 竊?50%<25>?- 譖エ譁ー蟾イ螳梧<E89EB3>蜉溯<E89C89>蛻苓。?- 譖エ譁ーDay 3-4螳梧<E89EB3><EFBFBD><E8ABA0>
- 譖エ譁ー荳倶ク€豁・蟾・菴懆ョ。蛻?
---
**莉サ蜉。13<31><EFBFBD>蟒コ菴ソ逕ィ謇句<E8AC87><E58FA5><EFBFBD>30蛻<30><EFBFBD>?*
**譁<>。」菴咲スョ**<2A>啻docs/03-荳壼苅讓。蝮<EFBDA1>/IIT Manager Agent/05-菴ソ逕ィ謇句<E8AC87>/莨∽ク壼セョ菫。蟇ケ隸晄欠蜊<E6ACA0>.md`
**譁<>。」蜀<EFBDA3>ョケ**<EFBFBD>?1. 莨∽ク壼セョ菫。蠎皮畑驟咲スョ
2. 逕ィ謌キ螯ゆス募刈蜈・蠎皮畑
3. 謾ッ謖∫噪蟇ケ隸晄欠莉、蛻苓。?4. 蟶ク隗<EFBDB8>琉鬚炉AQ
5.<>囿謗呈衍謖<E8A18D>
---
## 笨?蝗帙€ay 4扈捺據譌カ逧<EFBDB6>溜邇ッ謨域棡
### 4.1 螳梧紛髣ュ邇ッ鬪瑚ッ<E7919A>
```
<EFBFBD>識 譛€蟆舟VP髣ュ邇ッ螳悟<E89EB3>謇馴€夲シ<E5A4B2>
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?Step 1: REDCap謨ー謐ョ蠖募<E8A096> 笏?笏?笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?逕ィ謌キ蝨ィREDCap荳ュ<E88DB3><EFBDAD> 笏?笏?- 譁ー蠅樊ぅ閠<E38185>D 8 笏?笏?- 謌紋ソョ謾ケ謔」閠<EFBDA3>D 2 笏?笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏?0遘貞サカ霑? 竊?笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?Step 2: Node.js螳樊慮謐戊執 笏?笏?笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?笨?DET隗ヲ蜿<EFBDA6> (0遘? 笏?笏?笨?Webhook謗・謾カ (<10ms) 笏?笏?笨?Worker螟<72>炊 (~2遘? 笏?笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏? 竊?笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?Step 3: 莨∽ク壼セョ菫。謗ィ騾<EFBDA8>€夂衍 笏?笏?笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?笨?PI謾カ蛻ー蜊。迚<EFBDA1>カ域<EFBDB6> (<5遘? 笏?笏?笨?騾夂衍蜀<E8A18D>ョケ<EFBDAE>? 笏?笏? "<22>投 test0102 - 謨ー謐ョ蠖募<E8A096> 笏?笏? 蜿苓ッ戊€<E6888A><EFBFBD>8 笏?笏? 謫堺ス懶シ壽眠蠅? 笏?笏? 蠖募<E8A096>8荳ェ蟄玲ョ? 笏?笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏? 笏? 竊?笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?Step 4: PI蝨ィ莨∽ク壼セョ菫。荳ュ蟇ケ隸<EFBDB9> 笏?笏?笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?笏?笨?蜿鷹€<E9B7B9><EFBFBD>"譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€? 笏?笏?笨?AI蝗槫、搾シ? 笏?笏? "<22>投 譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€<C280><EFBDBB> 笏?笏? 譁ー蠅槫女隸戊€<E6888A><EFBFBD>2萓? 笏?笏? 謨ー謐ョ譖エ譁ー<E8AD81>?谺? 笏?笏? 笏?笏?笨?蜿鷹€<E9B7B9><EFBFBD>"譟・隸「謔」閠?逧<>ュ蜀? 笏?笏?笨?AI蝗槫、搾シ壽ぅ閠<E38185>渕譛ャ菫。諱? 笏?笏? 笏?笏?笨?蜿鷹€<E9B7B9><EFBFBD>"鬘ケ逶ョ霑帛コヲ" 笏?笏?笨?AI蝗槫、搾シ夐。ケ逶ョ扈溯ョ。謨ー謐? 笏?笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?```
### 4.2 鬪梧噺譬<E599BA><EFBFBD>域怙扈茨シ<E88CA8>
**蜉溯<E89C89>螳梧紛諤?*<2A>?- 笨?REDCap謨ー謐ョ螳樊慮逶大成<E5A4A7><E68890>ET + 霓ョ隸「<E99AB8>?- 笨?Node.js謨ー謐ョ謐戊執荳主、<E4B8BB><EFBDA4>?- 笨?莨∽ク壼セョ菫。騾夂衍謗ィ騾?- 笨?莨∽ク壼セョ菫。蟇ケ隸晄衍隸「
- 笨?螳。隶。譌・蠢怜ョ梧紛隶ー蠖<EFBDB0>
**諤ァ閭ス謖<EFBDBD><E8AC96><EFBFBD>**<2A>?| 謖<><E8AC96><EFBFBD> | 逶ョ譬<EFBDAE>€?| 螳樣刔蛟?| 迥カ諤?|
|------|--------|--------|------|
| DET隗ヲ蜿大サカ霑<EFBDB6> | <1遘?| 0遘?| 笨?|
| Webhook蜩榊コ疲慮髣エ | <100ms | <10ms | 笨?|
| 騾夂衍謗ィ騾∝サカ霑?| <10遘?| <5遘?| 笨?|
| 蟇ケ隸晏桃蠎疲慮髣エ | <5遘?| ~3遘?| 笨?|
| 謨ー謐ョ蜷梧ュ・蜃<EFBDA5>。ョ諤?| 100% | 100% | 笨?|
**謚€譛ッ謖<EFBDAF><E8AC96>?*<2A>?- 笨?莉」遐∫ャヲ蜷亥屬髦溯ァ<E6BAAF>
- 笨?髞呵ッッ螟<EFBDAF>炊螳悟埋
- 笨?譌・蠢苓ョー蠖募ョ梧紛
- 笨?豬玖ッ戊ヲ<E6888A>尠邇?90%
**蜿ッ貍皮、コ諤?*<2A>?- 笨?蜿ッ莉・邇ー蝨コ貍皮、コ螳梧紛髣ュ邇ッ
- 笨?蜿ッ莉・貍皮、コ蟇ケ隸晄衍隸「蜉溯<E89C89>
- 笨?謨域棡譏取仞縲∽サキ蛟シ貂<EFBDBC><E8B282>?
---
## <20>答 莠斐€∵橿譛ッ螳樒鴫扈<E9B4AB><E68988>?
### 5.1 莨∽ク壼セョ菫。蠑よュ・蝗槫、肴ィ。蠑擾シ芋沐?Critical<61>?
#### 髣ョ鬚俶緒霑ー
莨∽ク壼セョ菫。隕∵アり「ォ蜉ィ蝗槫、肴カ域<EFBFBD><EFBFBD>。サ蝨?*5遘貞<E98198>**螳梧<E89EB3>縲ょヲよ棡雜<E6A3A1><EFBFBD>檎畑謌キ莨夂恚蛻?譛榊苅證よ慮荳榊庄逕?逧<>署遉コ縲?
#### 髞呵ッッ蛛壽ウ<E5A3BD>
```typescript
笶?async handleCallback(request, reply) {
const message = parseMessage(request.body);
// 隹<>畑LLM<4C>亥庄閭ス閠玲慮10遘抵シ<E68AB5>
const answer = await classifyIntent(message);
const result = await queryData(answer);
// 雜<>慮莠<E685AE>シ∽シ∝セョ蟾イ譁ュ蠑€霑樊磁
return reply.send(result);
}
```
#### 豁」遑ョ蛛壽ウ包シ壼シよュ・蝗槫、肴ィ。蠑?```typescript
笨?async handleCallback(request, reply) {
const message = parseMessage(request.body);
// 1. 遶句叉霑泌屓'success'<27>?1遘抵シ<E68AB5>
reply.send('success');
// 2. 蠑よュ・螟<EFBDA5><EFBFBD>井ク埼仆蝪橸シ? setImmediate(async () => {
// 蜿ッ莉・諷「諷「邂暦シ<E69AA6>10遘偵€?0遘帝<E98198>蜿ッ莉・<E88E89>? const answer = await classifyIntent(message);
const result = await queryData(answer);
// 3. 菴ソ逕ィ荳サ蜉ィ謗ィ騾∵磁蜿」霑泌屓扈捺<E68988>? await wechatService.sendTextMessage(userId, result);
});
}
```
#### 蜈ウ髞ョ轤?1. 笨?**遶句叉霑泌屓**<2A>壽噺蛻ー豸域<E8B1B8><EFBFBD><1遘定ソ泌<EFBDBF>?success'
2. 笨?**蠑よュ・螟<EFBDA5>炊**<2A>壻スソ逕ィ`setImmediate`謌匁カ域<EFBDB6>髦溷<E9ABA6>?3. 笨?**荳サ蜉ィ謗ィ騾?*<2A>夊ー<E5A48A>畑蜿鷹€∵カ域<EFBDB6>謗・蜿」<E89CBF>€碁撼HTTP Response
4. 笨?**髞呵ッッ螟<EFBDAF>炊**<2A>壼シよュ・莉サ蜉。螟ア雍・譌カ<E8AD8C>梧耳騾∝暑螂ス髞呵ッッ謠千、?
---
### 5.2 莨∽ク壼セョ菫。XML蜉<4C>隗」蟇<EFBDA3>シ芋沐・ Critical<61>?
#### 髣ョ鬚俶緒霑ー
莨∽ク壼セョ菫。逧<EFBFBD>カ域<EFBFBD>菴捺<EFBFBD>?*蜉<><EFBFBD>噪XML**<2A>御ク肴弍譏取枚縲よ<E7B8B2>シ蠑丞ヲゆク具シ<E585B7>
```xml
<xml>
<ToUserName><![CDATA[ww01cb7b72ea2db83c]]></ToUserName>
<Encrypt><![CDATA[蜉<><EFBFBD>噪豸域<E8B1B8><EFBFBD>ョケ]]></Encrypt>
</xml>
```
#### 隗」蟇<EFBDA3>オ∫ィ<E288AB>
```
<EFBFBD><EFBFBD>ML 竊?Base64隗」遐<EFBDA3> 竊?AES隗」蟇<EFBDA3> 竊?蜴サ髯、Padding 竊?鬪瑚ッorpID 竊?譏取枚XML
```
#### 髞呵ッッ蛛壽ウ<E5A3BD>
```typescript
?// 閾ェ蟾ア螳樒鴫AES隗」蟇<EFBDA3>シ域栫譏灘<E8AD8F>髞呻シ<E591BB>
function decrypt(encryptedData) {
// 謇句<E8AC87>AES縲 ̄adding縲。ase64...
// 99%逧<>ココ驛ス莨壼<E88EA8><EFBFBD>
}
```
#### 豁」遑ョ蛛壽ウ包シ壻スソ逕ィ螳俶婿蠎<E5A9BF>
```bash
npm install @wecom/crypto
```
```typescript
?import { WXBizMsgCrypt } from '@wecom/crypto';
const crypt = new WXBizMsgCrypt(
process.env.WECHAT_TOKEN!, // 閾ェ螳壻ケ欝oken
process.env.WECHAT_ENCODING_AES_KEY!, // 莨∝セョ蜷主床逕滓<E98095><E6BB93>?3菴搾シ<E690BE>
process.env.WECHAT_CORP_ID!
);
// 荳€陦御サ」遐∝ョ梧<EFBDAE>隗」蟇?const decryptedXml = crypt.decrypt(
msg_signature,
timestamp,
nonce,
encryptedXml
);
```
#### 髴€隕∫噪驟咲スョ
| 驟咲スョ鬘?| 譚・貅<EFBDA5> | 遉コ萓<EFBDBA> |
|--------|------|------|
| `WECHAT_TOKEN` | 閾ェ螳壻ケ?| 32菴埼囂譛コ蟄礼ャヲ荳イ |
| `WECHAT_ENCODING_AES_KEY` | 莨∝セョ蜷主床逕滓<E98095> | 43菴榊ュ礼ャヲ<EFBDAC>亥ヲゑシ啾bcdefghijklmnopqrstuvwxyz0123456789ABC<42>?|
| `WECHAT_CORP_ID` | 莨∝セョ蜷主床 | ww01cb7b72ea2db83c |
---
### 5.3 莨∽ク壼セョ菫。IP逋ス蜷榊黒<E6A68A>芋沐・ P0<50>?
#### 髣ョ鬚俶緒霑ー
闔キ蜿泡ccessToken譌カ<EFBFBD>御シ∽ク壼セョ菫。莨壽<EFBFBD>。鬪瑚ッキ豎よ擂貅蝕P縲ょヲよ棡IP荳榊惠逋ス蜷榊黒荳ュ<EFBFBD>御シ夊ソ泌屓**60020髞呵ッッ**縲?
#### 驟咲スョ豁・鬪、
1. 遑ョ隶、SAE NAT鄂大<E98482>IP<49>啻182.92.176.14`
2. 逋サ蠖穂シ∽ク壼セョ菫。邂。逅<EFBDA1>錘蜿ー
3. 蠎皮畑邂。逅<EFBDA1> 竊?IIT Manager Agent
4. 謇セ蛻ー"莨∽ク壼庄菫。IP"驟咲スョ
5. 豺サ蜉<EFBDBB><E89C89>啻182.92.176.14`
6. 菫晏ュ伜ケカ豬玖ッ?
#### 鬪瑚ッ∵婿豕<E5A9BF>
```typescript
// 豬玖ッ柊ccessToken闔キ蜿<EFBDB7>
const response = await fetch(
`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${CORP_ID}&corpsecret=${SECRET}`
);
const data = await response.json();
if (data.errcode === 60020) {
console.error('笶?IP逋ス蜷榊黒譛ェ驟咲スョ<EFBDBD>?);
} else if (data.errcode === 0) {
console.log('?IP逋ス蜷榊黒驟咲スョ豁?);
}
```
---
### 5.4 莨∽ク壼セョ菫。豸域<E8B1B8>譬シ蠑<EFBDBC>
#### 譁<>悽豸域<E8B1B8>譬シ蠑<EFBDBC>
```json
{
"touser": "GaoFeng",
"msgtype": "text",
"agentid": 1000002,
"text": {
"content": "€<EFBFBD><EFBFBD>?
}
}
```
#### 蜊。迚<EFBDA1>カ域<EFBDB6>譬シ蠑<EFBDBC>
```json
{
"touser": "GaoFeng",
"msgtype": "textcard",
"agentid": 1000002,
"textcard": {
"title": "<22>投 test0102 - 謨ー謐ョ蠖募<E8A096>",
"description": "<div>蜿苓ッ戊€<E6888A><EFBFBD>8</div><div>謫堺ス懶シ壽眠蠅?/div><div>蠖募<E8A096>8荳ェ蟄玲ョ?/div>",
"url": "https://iit.xunzhengyixue.com/chat",
"btntxt": "譟・逵玖ッヲ諠<EFBDA6>"
}
}
```
### 5.5 莨∽ク壼セョ菫。蝗櫁ー<E6AB81>カ域<EFBDB6>譬シ蠑<EFBDBC>
#### 逕ィ謌キ譁<EFBDB7>悽豸域<E8B1B8><E59F9F><EFBFBD>ML譬シ蠑擾シ?```xml
<xml>
<ToUserName><![CDATA[ww01cb7b72ea2db83c]]></ToUserName>
<FromUserName><![CDATA[GaoFeng]]></FromUserName>
<CreateTime>1641024000</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€サ]]></Content>
<MsgId>1234567890</MsgId>
<AgentID>1000002</AgentID>
</xml>
```
#### 蝗槫、肴カ域<EFBDB6>譬シ蠑擾シ<E693BE>ML譬シ蠑擾シ?```xml
<xml>
<ToUserName><![CDATA[GaoFeng]]></ToUserName>
<FromUserName><![CDATA[ww01cb7b72ea2db83c]]></FromUserName>
<CreateTime>1641024001</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[<5B>投 譛€霑台ク€蜻ィ謨ー謐ョ豎<EFBDAE>€<C280><EFBDBB>
譁ー蠅槫女隸戊€<EFBFBD><EFBFBD>2萓?謨ー謐ョ譖エ譁ー<E8AD81>?谺。]]></Content>
</xml>
```
### 5.6 莨∽ク壼セョ菫。遲セ蜷埼ェ瑚ッ<E7919A>
```typescript
function verifySignature(signature: string, timestamp: string, nonce: string, echostr: string): boolean {
const token = WECHAT_TOKEN; // 莨∽ク壼セョ菫。驟咲スョ逧Уoken
const tmpArr = [token, timestamp, nonce, echostr].sort();
const tmpStr = tmpArr.join('');
const sha1 = crypto.createHash('sha1');
sha1.update(tmpStr);
const calculatedSignature = sha1.digest('hex');
return calculatedSignature === signature;
}
```
---
## <20>識 蜈ュ縲∽ク倶ク€豁・謇ゥ螻墓婿蜷托シ<E68998>hase 1.5+<2B>?
### Phase 1.5<EFBFBD>壽焚謐ョ雍ィ謗ァ隗<EFBFBD><EFBFBD>逕滓<EFBFBD><EFBFBD><EFBFBD>1-2螟ゥ<E89E9F><EFBDA9>
**逶ョ譬<EFBDAE>**<EFBFBD>壼ョ樒鴫蝓コ莠手ァ<EFBFBD><EFBFBD><EFBFBD>焚謐ョ雍ィ謗ァ
**譬ク蠢<EFBDB8>粥閭ス**<EFBFBD>?1. 荳贋シ<E8B48B>遐皮ゥカ譁ケ譯<EFBDB9>DF
2. AI閾ェ蜉ィ謠仙叙雍ィ謗ァ隗<EFBDA7><E99A97>
3.<><E99A97>蠎鍋ョ。逅<EFBDA1>シ亥庄郛冶セ代€∝庄螳。譬ク<E8ADAC>?4. 蝓コ莠手ァ<E6898B><EFBDA7>霑幄。梧焚謐ョ雍ィ謗ァ
5. 雍ィ謗ァ扈捺棡謗ィ騾∝芦莨∽ク壼セョ菫。
**謚€譛ッ譁ケ譯?*<2A>?- 菴ソ逕ィ螟ァ讓。蝙区署蜿冶ァ<E586B6><EFBDA7><EFBFBD>磯撼螳樊慮隹<E685AE><EFBFBD><E79591>
-<><E99A97>菫晏ュ伜芦謨ー謐ョ蠎難シ<E99BA3>quality_rules`陦ィ<E999A6><EFBDA8>
- 蠖募<E8A096>譌カ蝓コ莠手ァ<E6898B><EFBDA7>蛻、譁ュ<E8AD81>亥ソォ騾溘€∝庄髱<E5BA84><E9ABB1><EFBFBD>
- 隸∵紺體セ霑ス貅ッ<E8B285>郁ァ<E98381><EFBDA7>譚・貅蝉コ取婿譯育ャャX鬘オ隨ャY譚。<E8AD9A><EFBDA1>
---
### Phase 2<>啀C Workbench蜑咲ォッ<EFBDAB>?-3螟ゥ<E89E9F><EFBDA9>
**逶ョ譬<EFBDAE>**<EFBFBD>壽署萓娶eb遶ッ螟肴<EFBFBD>ク逡碁<EFBFBD>?
**譬ク蠢<EFBDB8>粥閭ス**<EFBFBD>?1. 雍ィ謗ァ蟒コ隶ョ蛻苓。ィ
2. 蠖灘燕謨ー謐ョ vs AI蟒コ隶ョ蟇ケ豈<EFBDB9>
3. 隸∵紺體セ螻慕、コ<EFBDA4><EFBDBA>DF鬮倅コョ<EFBDBA>?4. 螳。謇ケ謫堺ス懶シ育。ョ隶?諡堤サ晢シ?5. REDCap謨ー謐ョ蝗槫<E89D97>
---
### Phase 3<>壽匱閭ス蛹匁シ碑ソ幢シ磯柄譛滂シ<E6BB82>
**蜉溯<E89C89>謇ゥ螻<EFBDA9>**<EFBFBD>?1. 螟夊スョ蟇ケ隸晁<E99AB8><EFBFBD>
2. 荳贋ク区枚逅<E69E9A>ァ?3. 莉サ蜉。鬩ア蜉ィ蠑墓梼
4. 謔」閠<EFBDA3>囂隶ソAgent
5. 譎コ閭ス豎<EFBDBD>冠Agent
---
## <20>搭 荳<>€∵」€譟・貂<EFBDA5><E8B282>?
### Day 3蠑€蟋句燕
- [ ] 莨∽ク壼セョ菫。UserID遑ョ隶、<E99AB6>育畑莠取オ玖ッ包シ<E58C85>
- [ ] 莨∽ク壼セョ菫。蝗櫁ーザRL驟咲スョ<EFBDBD>亥惠莨∽ク壼セョ菫。邂。逅<EFBDA1>錘蜿ー<E89CBF>?- [ ] REDCap豬玖ッ墓焚謐ョ蜃<EFBDAE><EFBFBD>シ郁<EFBDBC>蟆?譚。<E8AD9A><EFBDA1>
- [ ] 蜷守ォッ譛榊苅霑占。梧ュ」蟶ク
### Day 3扈捺據譌?- [ ] WechatService蠑€蜿大ョ梧<EFBDAE>?- [ ] iit_quality_check Worker螳悟埋
- [ ] 莨∽ク壼セョ菫。謗ィ騾∵オ玖ッ暮€夊ソ<E5A48A>
- [ ] 遶ッ蛻ー遶ッ髣ュ邇ッ謇馴€夲シ<E5A4B2>EDCap 竊?莨∝セョ<EFBDBE>?
### Day 4扈捺據譌?- [ ] WechatCallbackController蠑€蜿大ョ梧<EFBDAE>?- [ ] 莨∽ク壼セョ菫。蟇ケ隸晏粥閭ス豬玖ッ暮€夊ソ<E5A48A>
- [ ] 螳梧紛髣ュ邇ッ蜴句鴨豬玖ッ暮€夊ソ<E5A48A>
- [ ]<>。」蜈ィ驛ィ譖エ譁ー螳梧<E89EB3>
- [ ] 莉」遐∵署莠、蛻ーGit
---
## <20>至 蜈ォ縲∵<E7B8B2>蜉滓<E89C89><E6BB93><EFBFBD>?
**MVP謌仙粥逧<E7B2A5><E980A7><EFBFBD>ソ?*<2A>?1. 笨?PI蜿ッ莉・蝨ィ莨∽ク壼セョ菫。荳ュ螳樊慮謾カ蛻ー謨ー謐ョ蠖募<E8A096>騾夂衍
2. 笨?PI蜿ッ莉・蝨ィ莨∽ク壼セョ菫。荳ュ譟・隸「鬘ケ逶ョ謨ー謐ョ
3. 笨?螳梧紛髣ュ邇ッ<E98287><EFBDAF>EDCap 竊?Node.js 竊?莨∝セョ<EFBDBE>臥ィウ螳夊ソ占。?4. 笨?蜩榊コ疲慮髣エ貊。雜ウ隕∵アゑシ?5遘抵シ<E68AB5>
5. 笨?蜿ッ莉・邇ー蝨コ貍皮、コ扈吝屬髦溽恚
**莉キ蛟シ鬪瑚ッ?*<2A>?- 笨?PI荳咲畑豈丞、ゥ逋サ蠖紐EDCap譟・逵玖ソ帛コヲ
- 笨?謨ー謐ョ蠖募<E8A096>蜷守ォ句叉遏・譎難シ御ク堺シ夐<EFBCA0>
- 笨?髫乗慮髫丞慍蜿ッ莉・譟・隸「謨ー謐ョ<E8AC90>域焔譛コ遶ッ<E981B6>?- 笨?荳コ蜷守サュ蜉溯<E89C89>謇ゥ螻墓遠荳句渕遑€
---
**譁<>。」扈エ謚、閠?*<2A>壼シ€蜿大屬髦?
**譛€蜷取峩譁?*<2A>?026-01-02
**迥カ諤?*<2A>夸沒?蠑€蜿題ョ。蛻抵シ亥セ<E4BAA5>鴬陦鯉シ<E9AF89>