Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
pms-dispatch-assistant
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
姜耀祖
pms-dispatch-assistant
Commits
5a1f974b
Commit
5a1f974b
authored
May 12, 2025
by
姜耀祖
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
funcation call测试
parent
6564ef5b
Pipeline
#21232
passed with stages
in 5 minutes and 5 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
348 additions
and
0 deletions
+348
-0
ChatController.java
...chassistant/controller/langchain/test/ChatController.java
+194
-0
ChatMessageDTO.java
...chassistant/controller/langchain/test/ChatMessageDTO.java
+18
-0
ChatMessageToolsDto.java
...istant/controller/langchain/test/ChatMessageToolsDto.java
+22
-0
Message.java
.../dispatchassistant/controller/langchain/test/Message.java
+14
-0
QWFuncation.java
...patchassistant/controller/langchain/test/QWFuncation.java
+21
-0
QWTool.java
...s/dispatchassistant/controller/langchain/test/QWTool.java
+17
-0
WeatherParameters.java
...ssistant/controller/langchain/test/WeatherParameters.java
+22
-0
WeatherTool.java
...patchassistant/controller/langchain/test/WeatherTool.java
+9
-0
index.html
src/main/resources/static/pages/test/index.html
+31
-0
No files found.
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/ChatController.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
org.apache.http.HttpHeaders
;
import
org.apache.http.HttpResponse
;
import
org.apache.http.client.methods.CloseableHttpResponse
;
import
org.apache.http.client.methods.HttpPost
;
import
org.apache.http.entity.ContentType
;
import
org.apache.http.entity.StringEntity
;
import
org.apache.http.impl.client.CloseableHttpClient
;
import
org.apache.http.impl.client.HttpClients
;
import
org.apache.http.impl.conn.PoolingHttpClientConnectionManager
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.servlet.mvc.method.annotation.SseEmitter
;
import
javax.annotation.PreDestroy
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.net.SocketTimeoutException
;
import
java.util.*
;
@RestController
@RequestMapping
(
"/test/chat"
)
public
class
ChatController
{
@Autowired
private
ObjectMapper
objectMapper
;
private
static
final
CloseableHttpClient
httpClient
;
private
static
final
String
QW_API_KEY
=
"sk-7849b6c296b04cbc8df78521c4e0ecb2"
;
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
ChatController
.
class
);
static
{
PoolingHttpClientConnectionManager
connManager
=
new
PoolingHttpClientConnectionManager
();
connManager
.
setMaxTotal
(
100
);
connManager
.
setDefaultMaxPerRoute
(
20
);
httpClient
=
HttpClients
.
custom
()
.
setConnectionManager
(
connManager
)
.
build
();
}
@GetMapping
(
value
=
"/chat-stream"
,
produces
=
"text/event-stream;charset=UTF-8"
)
public
SseEmitter
chatStream
(
@RequestParam
(
"message"
)
String
message
,
HttpServletResponse
rresponse
)
throws
IOException
{
SseEmitter
emitter
=
new
SseEmitter
(
30
*
60
*
1000L
);
List
<
Message
>
messages
=
new
ArrayList
<>();
Message
m
=
new
Message
();
m
.
setRole
(
"user"
);
m
.
setContent
(
message
);
messages
.
add
(
m
);
rresponse
.
setStatus
(
HttpServletResponse
.
SC_OK
);
rresponse
.
setContentType
(
"text/event-stream;charset=UTF-8"
);
rresponse
.
setCharacterEncoding
(
"UTF-8"
);
rresponse
.
flushBuffer
();
new
Thread
(()
->
{
try
{
//tool工具构建
WeatherParameters
weatherParameters
=
new
WeatherParameters
();
Map
<
String
,
Object
>
parametersMap
=
new
HashMap
<>();
Map
<
String
,
Object
>
parameters
=
new
HashMap
<>();
parameters
.
put
(
"type"
,
"string"
);
parameters
.
put
(
"description"
,
"专家的专业领域或关键词,如\"通信\"或\"运维\""
);
Map
<
String
,
Object
>
parameters1
=
new
HashMap
<>();
parameters1
.
put
(
"type"
,
"string"
);
parameters1
.
put
(
"description"
,
"可选 专家所在的城市,如\"南京\"或\"苏州\""
);
parametersMap
.
put
(
"query"
,
parameters
);
parametersMap
.
put
(
"city"
,
parameters1
);
weatherParameters
.
setType
(
"object"
);
weatherParameters
.
setProperties
(
parametersMap
);
QWFuncation
qwFuncation
=
new
QWFuncation
();
qwFuncation
.
setName
(
"search_expert"
);
qwFuncation
.
setDescription
(
"据专业领域和可选地市,查找符合条件的自有人员专家列表"
);
qwFuncation
.
setParameters
(
weatherParameters
);
QWTool
qwTool
=
new
QWTool
();
qwTool
.
setType
(
"function"
);
qwTool
.
setFunction
(
qwFuncation
);
List
<
QWTool
>
qwTools
=
new
ArrayList
<>();
qwTools
.
add
(
qwTool
);
// 请求体构建优化
// ChatMessageDTO messageDTO = new ChatMessageDTO("qwq-plus",
// messages, true);
ChatMessageToolsDto
messageDTO
=
new
ChatMessageToolsDto
(
"qwq-plus"
,
messages
,
true
,
qwTools
);
// 使用HttpComponents更优雅的请求构建方式
String
reuqestData
=
objectMapper
.
writeValueAsString
(
messageDTO
);
HttpPost
post
=
new
HttpPost
(
"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions"
);
post
.
setHeader
(
HttpHeaders
.
AUTHORIZATION
,
"Bearer "
+
QW_API_KEY
);
post
.
setEntity
(
new
StringEntity
(
reuqestData
,
ContentType
.
APPLICATION_JSON
));
log
.
info
(
"发起对话请求:"
+
reuqestData
);
// 执行请求(带重试)
try
(
CloseableHttpResponse
response
=
httpClient
.
execute
(
post
))
{
log
.
info
(
"请求成功!"
);
processStreamResponse
(
response
,
emitter
);
}
}
catch
(
Exception
e
)
{
handleException
(
e
,
emitter
);
}
}).
start
();
// 超时和完成回调
emitter
.
onTimeout
(()
->
log
.
warn
(
"SSE连接超时"
));
emitter
.
onCompletion
(()
->
log
.
info
(
"SSE连接完成"
));
return
emitter
;
}
// 流式响应处理私有方法
private
void
processStreamResponse
(
HttpResponse
response
,
SseEmitter
emitter
)
throws
IOException
{
StringBuilder
toolArgumentsBuffer
=
new
StringBuilder
();
boolean
isToolCalling
=
false
;
String
toolName
=
null
;
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
response
.
getEntity
().
getContent
())))
{
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
if
(!
line
.
startsWith
(
"data: "
))
continue
;
String
jsonStr
=
line
.
substring
(
6
).
trim
();
if
(
"[DONE]"
.
equals
(
jsonStr
))
break
;
JsonNode
node
=
objectMapper
.
readTree
(
jsonStr
);
JsonNode
delta
=
node
.
at
(
"/choices/0/delta"
);
// 处理工具调用
if
(
delta
.
has
(
"tool_calls"
))
{
isToolCalling
=
true
;
JsonNode
toolCall
=
delta
.
get
(
"tool_calls"
).
get
(
0
);
if
(
toolName
==
null
&&
toolCall
.
has
(
"function"
)
&&
toolCall
.
get
(
"function"
).
has
(
"name"
))
{
toolName
=
toolCall
.
get
(
"function"
).
get
(
"name"
).
asText
();
}
String
part
=
toolCall
.
get
(
"function"
).
path
(
"arguments"
).
asText
(
""
);
toolArgumentsBuffer
.
append
(
part
);
continue
;
}
// 处理普通 content 输出
String
content
=
delta
.
path
(
"content"
).
asText
(
null
);
String
reasoning
=
delta
.
path
(
"reasoning_content"
).
asText
(
null
);
if
(
content
==
null
||
content
.
isEmpty
())
{
continue
;
}
log
.
info
(
content
);
emitter
.
send
(
SseEmitter
.
event
().
data
(
content
).
id
(
UUID
.
randomUUID
().
toString
()));
}
if
(
isToolCalling
)
{
String
toolArgumentsJson
=
toolArgumentsBuffer
.
toString
();
JsonNode
args
=
objectMapper
.
readTree
(
toolArgumentsJson
);
String
city
=
args
.
path
(
"city"
).
asText
();
String
query
=
args
.
path
(
"query"
).
asText
();
log
.
info
(
"准备调用工具函数 {}: city={}, query={}"
,
toolName
,
city
,
query
);
String
result
=
searchExpert
(
city
,
query
);
emitter
.
send
(
SseEmitter
.
event
().
data
(
result
).
id
(
UUID
.
randomUUID
().
toString
()));
}
emitter
.
complete
();
}
}
private
String
searchExpert
(
String
city
,
String
query
)
{
return
"为您推荐如下专家:姓名:张三,城市:"
+
city
+
", 领域:"
+
query
+
",荣誉:。。。"
;
}
@PreDestroy
public
void
destroy
()
throws
IOException
{
httpClient
.
close
();
// 程序退出时关闭
}
// 统一异常处理
private
void
handleException
(
Exception
e
,
SseEmitter
emitter
)
{
log
.
error
(
"API调用异常"
,
e
);
if
(
e
instanceof
SocketTimeoutException
)
{
emitter
.
completeWithError
(
new
RuntimeException
(
"连接DeepSeek服务超时"
));
}
else
{
emitter
.
completeWithError
(
new
RuntimeException
(
"服务内部错误"
));
}
}
}
\ No newline at end of file
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/ChatMessageDTO.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.Getter
;
import
lombok.Setter
;
import
java.util.List
;
@Getter
@Setter
@AllArgsConstructor
public
class
ChatMessageDTO
{
private
String
model
;
private
List
<
Message
>
messages
;
private
boolean
stream
;
public
ChatMessageDTO
(){}
}
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/ChatMessageToolsDto.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
lombok.Setter
;
import
java.util.List
;
/**
* @author jiangyz
* @date 2025/5/9 14:32
*/
@Getter
@Setter
@AllArgsConstructor
public
class
ChatMessageToolsDto
{
private
String
model
;
private
List
<
Message
>
messages
;
private
boolean
stream
;
private
List
<
QWTool
>
tools
;
public
ChatMessageToolsDto
(){}
}
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/Message.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
lombok.Setter
;
@Getter
@Setter
@AllArgsConstructor
public
class
Message
{
private
String
role
;
private
String
content
;
public
Message
(){}
}
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/QWFuncation.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
lombok.NoArgsConstructor
;
import
lombok.Setter
;
import
org.apache.poi.ss.formula.functions.T
;
/**
* @author jiangyz
* @date 2025/5/9 13:49
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public
class
QWFuncation
{
private
String
name
;
private
String
description
;
private
Object
parameters
;
}
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/QWTool.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
import
lombok.*
;
import
org.apache.poi.ss.formula.functions.T
;
/**
* @author jiangyz
* @date 2025/5/9 13:49
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public
class
QWTool
{
private
String
type
;
private
QWFuncation
function
;
}
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/WeatherParameters.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
lombok.NoArgsConstructor
;
import
lombok.Setter
;
import
java.util.List
;
import
java.util.Map
;
/**
* @author jiangyz
* @date 2025/5/9 13:53
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public
class
WeatherParameters
{
private
String
type
;
private
Map
<
String
,
Object
>
properties
;
}
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/test/WeatherTool.java
0 → 100644
View file @
5a1f974b
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
controller
.
langchain
.
test
;
/**
* @author jiangyz
* @date 2025/5/9 13:48
*/
public
class
WeatherTool
{
}
src/main/resources/static/pages/test/index.html
0 → 100644
View file @
5a1f974b
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<title>
Title
</title>
</head>
<body>
<div>
<input
type=
"text"
id=
"input"
placeholder=
"输入问题..."
>
<button
onclick=
"startChat()"
>
发送
</button>
<div
id=
"output"
style=
"white-space: pre-wrap;"
></div>
</div>
<script>
function
startChat
()
{
const
input
=
document
.
getElementById
(
'input'
).
value
;
const
eventSource
=
new
EventSource
(
`/dispatch-assistant/test/chat/chat-stream?message=
${
encodeURIComponent
(
input
)}
`
);
eventSource
.
onmessage
=
(
e
)
=>
{
document
.
getElementById
(
'output'
).
textContent
+=
e
.
data
;
window
.
scrollTo
(
0
,
document
.
body
.
scrollHeight
);
};
eventSource
.
onerror
=
()
=>
{
eventSource
.
close
();
//alert('连接异常,请重试!');
};
}
</script>
</body>
</html>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment