前端搭建 MCP Client(Web版)+ Server + Agent 实践
itomcoil 2025-04-26 18:47 9 浏览
关注更多AI编程资讯请去AI Coding专区:
https://juejin.cn/aicoding
先上个效果图,上图是在 web 版 Client 中使用 todoist-mcp-server 帮我新建了一条 todolist。
本文主要介绍整体的思路和实现以及踩坑记录。
前言
MCP(Model Context Protocol)是一种开放协议,旨在通过标准化接口实现大语言模型(LLMs)与外部数据源及工具的无缝集成。MCP由 Anthropic 公司在2024年底推出,其设计理念类似于USB接口,为AI模型提供了一个“即插即用”的扩展能力,使其能够轻松连接至不同的工具和数据源。想深入了解可查看 官方文档,这里只做实战经验分享。
概念介绍
MCP Hosts(MCP 应用):如Claude Desktop、IDE、AI应用等,希望通过MCP访问数据或工具。MCP Clients(MCP 客户端):与一对一与服务端进行连接,相当于我们应用中实现数据库交互需要实现的一个客户端。MCP Servers(MCP 服务端):基于MCP协议实现特定功能的程序。Local Data Sources:本地数据源,公MCP服务器进行本地访问。Remote Services:远端服务,供MCP服务器访问远端访问,例如api的方式。
本文主要搭建 Web 版本的 MCP Client 和 MCP Server。
技术栈
系统要求:Node.js >= 18(本地用了v20)
核心依赖库:CopilotKit、LangChain及其生态。
- CopilotKit:React UI + 适用于 AI Copilot、AI 聊天机器人和应用内 AI 代理的优雅基础架构。
- LangChain.js 和 LangGraph:LangChain相关主要用于开发agent。
- langchainjs-mcp-adapters :提供了一个轻量级的包装器,使得 MCP 与 LangChain.js 兼容。
- modelcontextprotocol/typescript-sdk:MCP TypeScript SDK
- open-mcp-client:CopilotKit 开源的 MCP Client。
- mcp-server-supos:一个可用的 MCP Server。
Client
页面大概这样,包括:左侧管理MCP Server、右侧聊天机器人
技术方案
声明:此 Client 是基于CopilotKit 开源的 MCP Client open-mcp-client 二次改造
该代码库主要分为两个部分:
- /agent – 连接到 MCP Server并调用其工具的LangGraph代理(Python)。
- /app – 使用 CopilotKit 进行UI和状态同步的前端应用程序(Next.js)。
由于 Python 的 agent 在 Windows 环境下运行时报错:
本人Python编码能力有限,基于此改造成了基于 JS 的 agent(/agent-js部分),后续均以agent-js为例;想用 Python 的也可按后续的改动点对 /agent 进行修改。
一、agent部分
文件结构
核心代码
「agent.js」 - 基于 langgraph 创建 workflow,其中主要节点为 chat_node,该节点功能点:
- 定义LLM
import { ChatOpenAI } from"@langchain/openai";// import { HttpsProxyAgent } from "https-proxy-agent";// const agentProxy = new HttpsProxyAgent("http://127.0.0.1:xxxx");...// 1 Define the modelconst model = new ChatOpenAI( { temperature: 0, model: "gpt-4o", }, // todo: test, 走本地代理便于翻墙 // { // httpAgent: agentProxy, // } );...
「注意:本地联调需访问 openai 时,如果是使用的代理工具,还是需要在代码里指定代理地址(HttpsProxyAgent)」
- 从 state 获取 MCP Server Configs,创建 MCP Client 连接到 MCP Server,连通后获取 Server 的 tools。(@langchain/mcp-adapters)
const mcpConfig: any = state.mcp_config || {};// 重要:设置环境变量时,最好把当前进程的环境变量也传递过去,确保执行Server的子进程需要的环境变量都存在let newMcpConfig: any = {};Object.keys(mcpConfig).forEach((key) => { newMcpConfig[key] = { ...mcpConfig[key] }; if (newMcpConfig[key].env) { newMcpConfig[key].env = { ...process.env, ...newMcpConfig[key].env }; } });console.log("****mcpConfig****", mcpConfig);// 2 Create clientconst client = new MultiServerMCPClient(newMcpConfig);// examples// const client = new MultiServerMCPClient({// math: {// transport: "stdio",// command: "npx",// args: ["-y", "mcp-server-supos"],// env: {"SUPOS_API_KEY": "xxxxx"}// },// });// 3 Initialize connection to the serverawait client.initializeConnections();const tools = client.getTools();
- 基于 model 和 tools 创建代理,并调用模型发送状态中的消息
// 4 Create the React agent width model and tools const agent = createReactAgent({ llm: model, tools, }); // 5 Invoke the model with the system message and the messages in the state const response = await agent.invoke({ messages: state.messages });
「完整代码」
agent.js
/** * This is the main entry point for the agent. * It defines the workflow graph, state, tools, nodes and edges. */import { RunnableConfig } from"@langchain/core/runnables";import { MemorySaver, START, StateGraph, Command, END,} from"@langchain/langgraph";import { createReactAgent } from"@langchain/langgraph/prebuilt";import { Connection, MultiServerMCPClient } from"@langchain/mcp-adapters";import { AgentState, AgentStateAnnotation } from"./state";import { getModel } from"./model";// 判断操作系统const isWindows = process.platform === "win32";const DEFAULT_MCP_CONFIG: Record<string, Connection> = {supos: { command: isWindows ? "npx.cmd" : "npx", args: [ "-y", "mcp-server-supos", ], env: { SUPOS_API_URL: process.env.SUPOS_API_URL || "", SUPOS_API_KEY: process.env.SUPOS_API_KEY || "", SUPOS_MQTT_URL: process.env.SUPOS_MQTT_URL || "", }, transport: "stdio", },};asyncfunction chat_node(state: AgentState, config: RunnableConfig) {// 1 Define the modelconst model = getModel(state);const mcpConfig: any = { ...DEFAULT_MCP_CONFIG, ...(state.mcp_config || {}) };// 重要:设置环境变量时,最好把当前进程的环境变量也传递过去,确保执行Server的子进程需要的环境变量都存在let newMcpConfig: any = {};Object.keys(mcpConfig).forEach((key) => { newMcpConfig[key] = { ...mcpConfig[key] }; if (newMcpConfig[key].env) { newMcpConfig[key].env = { ...process.env, ...newMcpConfig[key].env }; } });console.log("****mcpConfig****", mcpConfig);// 2 Create clientconst client = new MultiServerMCPClient(newMcpConfig);// const client = new MultiServerMCPClient({// math: {// transport: "stdio",// command: "npx",// args: ["-y", "mcp-server-supos"],// env: {"SUPOS_API_KEY": "xxxxx"}// },// });// 3 Initialize connection to the serverawait client.initializeConnections();const tools = client.getTools();// 4 Create the React agent width model and toolsconst agent = createReactAgent({ llm: model, tools, });// 5 Invoke the model with the system message and the messages in the stateconst response = await agent.invoke({ messages: state.messages });// 6 Return the response, which will be added to the statereturn [ new Command({ goto: END, update: { messages: response.messages }, }), ];}// Define the workflow graphconst workflow = new StateGraph(AgentStateAnnotation) .addNode("chat_node", chat_node) .addEdge(START, "chat_node");const memory = new MemorySaver();exportconst graph = workflow.compile({checkpointer: memory,});
model.js
/** * This module provides a function to get a model based on the configuration. */import { BaseChatModel } from"@langchain/core/language_models/chat_models";import { AgentState } from"./state";import { ChatOpenAI } from"@langchain/openai";import { ChatAnthropic } from"@langchain/anthropic";import { ChatMistralAI } from"@langchain/mistralai";// import { HttpsProxyAgent } from "https-proxy-agent";// todo test agentProxy// const agentProxy = new HttpsProxyAgent("http://127.0.0.1:7897");function getModel(state: AgentState): BaseChatModel {/** * Get a model based on the environment variable. */const stateModel = state.model;const stateModelSdk = state.modelSdk;// 解密const stateApiKey = atob(state.apiKey || "");const model = process.env.MODEL || stateModel;console.log( `Using stateModelSdk: ${stateModelSdk}, stateApiKey: ${stateApiKey}, stateModel: ${stateModel}` );if (stateModelSdk === "openai") { returnnew ChatOpenAI({ temperature: 0, model: model || "gpt-4o", apiKey: stateApiKey || undefined, } // { // httpAgent: agentProxy, // } ); }if (stateModelSdk === "anthropic") { returnnew ChatAnthropic({ temperature: 0, modelName: model || "claude-3-7-sonnet-latest", apiKey: stateApiKey || undefined, }); }if (stateModelSdk === "mistralai") { returnnew ChatMistralAI({ temperature: 0, modelName: model || "codestral-latest", apiKey: stateApiKey || undefined, }); }thrownewError("Invalid model specified");}export { getModel };
state.js
import { Annotation } from"@langchain/langgraph";import { CopilotKitStateAnnotation } from"@copilotkit/sdk-js/langgraph";import { Connection } from"@langchain/mcp-adapters";// Define the AgentState annotation, extending MessagesStateexportconst AgentStateAnnotation = Annotation.Root({model: Annotation<string>,modelSdk: Annotation<string>,apiKey: Annotation<string>,mcp_config: Annotation<Connection>, ...CopilotKitStateAnnotation.spec,});export type AgentState = typeof AgentStateAnnotation.State;
构建和运行
- 定义 langgraph.json 配置文件,定义 agent 相关配置,比如agent名称:sample_agent等
{ "node_version": "20","dockerfile_lines": [],"dependencies": ["."],"graphs": { "sample_agent": "./src/agent.ts:graph"// 定义agent名称等,用于前端指定使用 },"env": ".env"// 指定环境变量从.env文件中获取,生产环境可以删除该配置,从系统变量中获取}
在本地运行时,在根路径 /agent-js 添加 .env 文件
LANGSMITH_API_KEY=lsv2_...
OPENAI_API_KEY=sk-...
2.借助命令行工具@langchain/langgraph-cli进行构建和运行,在
package.json 中定义脚本:
"scripts": { "start": "npx @langchain/langgraph-cli dev --host localhost --port 8123", "dev": "npx @langchain/langgraph-cli dev --host localhost --port 8123 --no-browser" },
加上--no-browser不会自动打开本地调试的studio页面
运行后可以在Studio预览联调等
(Studio:https://smith.langchain.com/studio/thread?baseUrl=http%3A%2F%2Flocalhost%3A8123)
注意点(踩坑记录)
1. 引入modelcontextprotocol/
typescript-sdk报错:
@modelcontextprotocol/sdk fails in CommonJS projects due to incompatible ESM-only dependency (pkce-challenge)
主要是modelcontextprotocol/
typescript-sdk的cjs包里面引用的pkce-challenge不支持cjs
官方的issues也有提出些解决方案,但目前为止官方还未发布解决了该问题的版本
「解决:package.json 添加"type": "module" 字段,声明项目使用 「ES Modules (ESM)」 规范」
2. 配置 MCP Server 环境变量 env 问题
例如:Node.js 的 child_process.spawn() 方法无法找到例如 npx 等可执行文件。
「环境变量 PATH 缺失」,系统未正确识别 npx 的安装路径。
可能的原因:
1)MCP Server配置了 env 参数后,导致传入的 env 覆盖了默认从父进程获取的环境变量
「解决:对配置了 env 的 Server,将当前的环境变量合并传入」
const mcpConfig: any = state.mcp_config || {}; // 重要:设置环境变量时,最好把当前进程的环境变量也传递过去,确保执行Server的子进程需要的环境变量都存在 let newMcpConfig: any = {}; Object.keys(mcpConfig).forEach((key) => { newMcpConfig[key] = { ...mcpConfig[key] }; if (newMcpConfig[key].env) { newMcpConfig[key].env = { ...process.env, ...newMcpConfig[key].env }; } });
2) 「跨平台路径问题」:比如在 Windows 中直接调用 npx 需使用 npx.cmd
// 判断操作系统const isWindows = process.platform === "win32";const DEFAULT_MCP_CONFIG: Record<string, Connection> = {supos: { command: isWindows ? "npx.cmd" : "npx", args: [ "-y", "mcp-server-supos", ], env: { SUPOS_API_URL: process.env.SUPOS_API_URL || "", SUPOS_API_KEY: process.env.SUPOS_API_KEY || "", SUPOS_MQTT_URL: process.env.SUPOS_MQTT_URL || "", }, transport: "stdio", },};
二、前端应用部分
前端应用部分改动主要是页面上的一些功能添加等,例如支持选模型,支持配置 env 参数等,页面功能相关的内容就略过,可以直接看 open-mcp-client,这里简单介绍下整体的一个架构。
架构方案
主要是 CopilotKit + Next.js,先看下 「CopilotKit」 官方的一个架构图:
根据本文实际用到的简化下(本文采用的 CoAgents模式)
核心代码(以Next.js为例)
核心依赖 @copilotkit/react-ui @copilotkit/react-core @copilotkit/runtime
1. 设置运行时端点
/app/api/copilotkit/route.ts:设置 agent 远程端点
import { CopilotRuntime, ExperimentalEmptyAdapter, copilotRuntimeNextJSAppRouterEndpoint, langGraphPlatformEndpoint} from"@copilotkit/runtime";;import { NextRequest } from"next/server";// You can use any service adapter here for multi-agent support.const serviceAdapter = new ExperimentalEmptyAdapter();const runtime = new CopilotRuntime({ remoteEndpoints: [ langGraphPlatformEndpoint({ // agent部署地址 deploymentUrl: `${process.env.AGENT_DEPLOYMENT_URL || 'http://localhost:8123'}`, langsmithApiKey: process.env.LANGSMITH_API_KEY, agents: [ { name: 'sample_agent', // agent 名称 description: 'A helpful LLM agent.', } ] }), ],});exportconst POST = async (req: NextRequest) => { const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({ runtime, serviceAdapter, endpoint: "/api/copilotkit", }); return handleRequest(req);};
2. 页面接入 CopilotKit UI
/app/layout.tsx:页面最外层用 CopilotKit 包裹,配置 runtimeUrl 和 agent
import type { Metadata } from"next";import { Geist, Geist_Mono } from"next/font/google";import"./globals.css";import"@copilotkit/react-ui/styles.css";import { CopilotKit } from"@copilotkit/react-core";const geistSans = Geist({variable: "--font-geist-sans",subsets: ["latin"],});const geistMono = Geist_Mono({variable: "--font-geist-mono",subsets: ["latin"],});exportconst metadata: Metadata = {title: "Open MCP Client",description: "An open source MCP client built with CopilotKit ",};exportdefaultfunction RootLayout({ children,}: Readonly<{ children: React.ReactNode;}>) {return ( <html lang="en"> <body className={`${geistSans.variable} ${geistMono.variable} antialiased w-screen h-screen`} > <CopilotKit runtimeUrl="/api/copilotkit" agent="sample_agent" showDevConsole={false} > {children} </CopilotKit> </body> </html> );}
/app/page.tsx:选择需要的聊天组件,例如 CopilotPopup
"use client";import { CopilotPopup } from "@copilotkit/react-ui";export function Home() { return ( <> <YourMainContent /> <CopilotChat className="h-full flex flex-col" instructions={ "Youareassistingtheuserasbestasyoucan.Answerinthebestwaypossiblegiventhedatayouhave." } labels={{ title: "MCPAssistant", initial: "Needanyhelp?", }} /> </> );}
构建和运行
这里就参照 Next.js 官方即可
package.json
"scripts": { "dev-frontend": "pnpm i && next dev --turbopack", "dev-agent-js": "cd agent-js && pnpm i && npx @langchain/langgraph-cli dev --host 0.0.0.0 --port 8123 --no-browser", "dev-agent-py": "cd agent && poetry install && poetry run langgraph dev --host 0.0.0.0 --port 8123 --no-browser", "dev": "pnpx concurrently \"pnpm dev-frontend\" \"pnpm dev-agent-js\" --names ui,agent --prefix-colors blue,green", "build": "next build", "start": "next start", "lint": "next lint" },
Server
建议直接参考 MCP Server Typescript SDK 示例开发,官网文档的用法更新没那么及时,容易走弯路。
mcp-server-supos 是一个可用的 MCP Server,也发布了对应的 npm 包。
这里截取核心代码片段,想了解更多可点击查看源码和使用文档等。
核心代码
- 提供tool-调用API查询信息
- 实时订阅MQTT topic数据进行缓存,用于提供 tool 查询分析最新数据
- 示例 server.resource
index.ts
#!/usr/bin/env nodeimport { McpServer } from"@modelcontextprotocol/sdk/server/mcp.js";import { StdioServerTransport } from"@modelcontextprotocol/sdk/server/stdio.js";import fetch from"node-fetch";import { z } from"zod";import fs, { readFileSync } from"fs";import _ from"lodash";import mqtt from"mqtt";import { pathToFileURL } from"url";import { createFilePath } from"./utils.js";let SUPOS_API_URL = process.env.SUPOS_API_URL;let SUPOS_API_KEY = process.env.SUPOS_API_KEY;let SUPOS_MQTT_URL = process.env.SUPOS_MQTT_URL;if (!SUPOS_API_URL) {console.error("SUPOS_API_URL environment variable is not set"); process.exit(1);}if (!SUPOS_API_KEY) {console.error("SUPOS_API_KEY environment variable is not set"); process.exit(1);}const filePath = createFilePath();const fileUri = pathToFileURL(filePath).href;asyncfunction getModelTopicDetail(topic: string): Promise<any> {const url = `${SUPOS_API_URL}/open-api/supos/uns/model?topic=${encodeURIComponent( topic )}`;const response = await fetch(url, { headers: { apiKey: `${SUPOS_API_KEY}`, }, });if (!response.ok) { thrownewError(`SupOS API error: ${response.statusText}`); }returnawait response.json();}function getAllTopicRealtimeData() {// 缓存实时数据,定时写入缓存文件const cache = newMap();let timer: any = null;const options = { clean: true, connectTimeout: 4000, clientId: "emqx_topic_all", rejectUnauthorized: false, reconnectPeriod: 0, // 不进行重连 };const connectUrl = SUPOS_MQTT_URL;if (!connectUrl) { return; }const client = mqtt.connect(connectUrl, options); client.on("connect", function () { client.subscribe("#", function (err) { // console.log("err", err); }); }); client.on("message", function (topic, message) { cache.set(topic, message.toString()); }); client.on("error", function (error) { // console.log("error", error); }); client.on("close", function () { if (timer) { clearInterval(timer); } });// 每 5 秒批量写入一次 timer = setInterval(() => { const cacheJson = JSON.stringify( Object.fromEntries(Array.from(cache)), null, 2 ); // 将更新后的数据写入 JSON 文件 fs.writeFile( filePath, cacheJson, { encoding: "utf-8", }, (error) => { if (error) { fs.writeFile( filePath, JSON.stringify({ msg: "写入数据失败" }, null, 2), { encoding: "utf-8" }, () => {} ); } } ); }, 5000);}function createMcpServer() {const server = new McpServer( { name: "mcp-server-supos", version: "0.0.1", }, { capabilities: { tools: {}, }, } );// Static resource server.resource("all-topic-realtime-data", fileUri, async (uri) => ({ contents: [ { uri: uri.href, text: readFileSync(filePath, { encoding: "utf-8" }), }, ], })); server.tool( "get-model-topic-detail", { topic: z.string() }, async (args: any) => { const detail = await getModelTopicDetail(args.topic); return { content: [{ type: "text", text: `${JSON.stringify(detail)}` }], }; } ); server.tool("get-all-topic-realtime-data", {}, async () => { return { content: [ { type: "text", text: readFileSync(filePath, { encoding: "utf-8" }), }, ], }; });asyncfunction runServer() { const transport = new StdioServerTransport(); const serverConnect = await server.connect(transport); console.error("SupOS MCP Server running on stdio"); return serverConnect; } runServer().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });}asyncfunction main() {try { createMcpServer(); getAllTopicRealtimeData(); } catch (error) { console.error("Error in main():", error); process.exit(1); }}main();
utils.ts
import fs from"fs";import path from"path";exportfunction createFilePath( filedir: string = ".cache", filename: string = "all_topic_realdata.json") {// 获取项目根路径const rootPath = process.cwd();// 创建缓存目录const filePath = path.resolve(rootPath, filedir, filename);const dirPath = path.dirname(filePath);// 检查目录是否存在,如果不存在则创建if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); }return filePath;}exportfunction readFileSync(filePath: string, options: any) {try { return fs.readFileSync(filePath, options); } catch (err) { return`读取文件时出错: ${err}`; }}
如何使用
「Client」:目前支持MCP协议的客户端已有很多,比如桌面端应用 Claude for Desktop,或者IDE的一些插件等(VSCode 的 Cline 插件),想了解已支持的客户端可访问 Model Context Protocol Client
「Server」:除了官方例子Model Context Protocol Client 外,已有很多网站整合了 MCP Servers,例如 mcp.so, Glama 等。
下面列举几个介绍下:
1. 配合本文 web 版 Client 使用(以todoist-mcp-server为例子)
1)配置
2)使用
2. 配合 Claude 使用
具体可参考:mcp-server-supos README.md,服务换成自己需要的即可
3. 使用 VSCode 的 Cline 插件
由于使用 npx 找不到路径,这里以 node 执行本地文件为例
1)配置
2)使用
结语
以上便是近期使用 MCP 的一点小经验~
整理完后看了下,如果只是单纯想集成些 MCP Server,其实可以不用 agent 形式,直接使用 copilotkit 的标准模式,在本地服务调用 langchainjs-mcp-adapters 和 LLM 即可,例如:
import { CopilotRuntime, LangChainAdapter, copilotRuntimeNextJSAppRouterEndpoint,} from'@copilotkit/runtime';import { ChatOpenAI } from"@langchain/openai";import { NextRequest } from'next/server';// todo: 调用 @langchain/mcp-adapters 集成 MCP Server 获取 tools 给到大模型 ...const model = new ChatOpenAI({ model: "gpt-4o", apiKey: process.env.OPENAI_API_KEY });const serviceAdapter = new LangChainAdapter({ chainFn: async ({ messages, tools }) => { return model.bindTools(tools).stream(messages); // or optionally enable strict mode // return model.bindTools(tools, { strict: true }).stream(messages); }});const runtime = new CopilotRuntime();exportconst POST = async (req: NextRequest) => {const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({ runtime, serviceAdapter, endpoint: '/api/copilotkit', });return handleRequest(req);};
但这样可能少了些上下文状态等,具体可以下来都试试~
相关推荐
- PS小技巧 调整命令,让人物肤色变得更加白皙 #后期修图
-
我们来看一下如何去将人物的皮肤变得更加的白皙。·首先选中图层,Ctrl键加J键复制一层。·打开这里的属性面板,选择快速操作删除背景,这样就会将人物进行单独的抠取。·接下来在上方去添加一个黑白调整图层,...
- 把人物肤色提亮的方法和技巧
-
PS后期调白肤色提亮照片的方法。一白遮百丑,所以对于Photoshop后期来说把人物肤色调白是一项非常重要的任务。就拿这张素材图片来说,这张素材图片人脸的肤色主要偏红、偏黄,也不够白皙,该怎样对它进行...
- 《Photoshop教程》把美女图片调成清爽色彩及润肤技巧
-
关注PS精品教程,每天不断更新~~室内人物图片一般会偏暗,人物脸部、肤色及背景会出现一些杂点。处理之前需要认真的给人物磨皮及美白,然后再整体润色。最终效果原图一、用修补工具及图章工具简单去除大一点的黑...
- PS后期对皮肤进行美白的技巧
-
PS后期进行皮肤美白的技巧。PS后期对皮肤进行美白的技巧:·打开素材图片之后直接复制原图。·接下来直接点击上方的图像,选择应用图像命令。·在通道这里直接选择红通道,混合这里直接选择柔光,然后点击确定。...
- 493 [PS调色]调模特通透肤色
-
效果对比:效果图吧:1、光位图:2、拍摄参数:·快门:160;光圈:8;ISO:1003、步骤分解图:用曲线调整图层调出基本色调。用可选颜色调整图层调整红色、黄色、白色和灰色4种颜色的混合比例。用色彩...
- 先选肤色再涂面部,卡戴珊的摄影师透露:为明星拍完照后怎么修图
-
据英国媒体12月17日报道,真人秀明星金·卡戴珊终于承认,她把女儿小北P进了家族的圣诞贺卡,怪不得粉丝们都表示这张贺卡照得非常失败。上周,这位39岁的女星遭到了一些粉丝针对这张照片的批评,她于当地时间...
- 如何在PS中运用曲线复制另一张照片的色调
-
怎样把另一张作品的外观感觉,套用到自己的照片上?单靠肉眼来猜,可能很不容易,而来自BenSecret的教学,关键是在PS使用了两个工具,让你可以准确比较两张照片的曝光、色调与饱和度,方便你调整及复制...
- PS在LAB模式下调出水嫩肤色的美女
-
本PS教程主要使用Photoshop使用LAB模式调出水嫩肤色的美女,教程调色比较独特。作者比较注重图片高光部分的颜色,增加质感及肤色调红润等都是在高光区域完成。尤其在Lab模式下,用高光选区调色后图...
- 在Photoshop图像后期处理中如何将人物皮肤处理得白皙通透
-
我们在人像后期处理中,需要将人物皮肤处理的白皙通透,处理方法很多,大多数都喜欢使用曲线、磨皮等进行调整,可以达到亮但是不透,最终效果往往不是很好,今天就教大家一种如何将任务皮肤处理得白皙通透,希望能帮...
- PS调色自学教程:宝宝照片快速调通透,简单实用!
-
PS调色自学教程:宝宝照片快速调通透。·首先复制图层,然后选择进入ACR滤镜,选择曲线锁定照片的亮部,也就高光位置,其他部位补亮一点,尤其是阴影的部位补亮多一些,让画面的层次均匀一点。·然后回到基本项...
- 【干货】如何利用PS进行人物美化
-
人物图像美化在Photoshop中非常常用,Photoshop作为一款功能强大的图像处理软件,不仅可以对人像进行基本的调色、美化和修复等处理,还可以改变人物的线条和幅度,如调整脸部器官和脸型的大小、调...
- 教大家一种可以快速把肤色处理均匀的方法@抖音短视频
-
快速把肤色处理均匀的方法。今天教大家一种可以快速把肤色处理均匀的方法。像这张照片整体肤色走紫红色,但是局部偏黄缘处理起来非常的麻烦。其实我们只需要新建空白图层,图层混合模式更改为颜色,再选择画笔工具把...
- PS调色教程 利用RAW调出干净通透的肤色
-
要么不发,要么干货。后期教程来噜~用RAW调出干净通透的肤色。这次终于不会原片比PS后好看了吧。如果你依然这么觉得,请不要残忍的告诉我这个事实,泪谢TAT)附送拍摄花絮,感谢各位的支持更多风格请关注m...
- photoshop后期皮肤变白的技巧
-
PS后期皮肤变白的技巧。1.PS后期让皮肤变白的方法有很多种,接下来教你一种非常简单容易上手的方法。2.打开素材图片之后,直接在小太极下拉框的位置添加一个纯色调整图层,颜色设置一个纯白色,点击...
- Photoshop调出人物的淡雅粉嫩肤色教程
-
本教程主要使用Photoshop调出人物的淡雅粉嫩肤色教程,最终的效果非常的通透迷人,下面让我们一起来学习.出自:86ps效果图:原图:1、打开原图复制一层。2、用Topaz滤镜磨皮(点此下载)。3、...
- 一周热门
- 最近发表
- 标签列表
-
- ps像素和厘米换算 (32)
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)